feat!: generate stealth statements from wallet api+new sending test - #1620
Conversation
WalkthroughBumps workspace version and adds a new utilities crate; renames and extends UTXO APIs (GetUnspent* → GetUtxos/ListUtxos) across indexer, storage, client, and bindings; migrates input-selection and signing model (ConfidentialTransferInputSelection → UtxoInputSelection; signing_key_id → seal_signer/other_signers/lock_ids); makes balance_proof optional; adds WalletLockDropGuard and traffic-sim. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Web UI / CLI
participant WalletD as Wallet Daemon
participant SDK as Wallet SDK
participant Store as Wallet Store
Client->>WalletD: create_stealth_transfer_statement(requests)
activate WalletD
WalletD->>SDK: generate_transfer_statement per request
activate SDK
SDK->>SDK: choose signer (account or nonce-derived)
SDK->>Store: create_lock() -> lock_id
Store-->>SDK: lock_id
SDK->>SDK: build statements (balance_proof Some/None)
SDK-->>WalletD: statements + signing_keys + lock_id
deactivate SDK
WalletD-->>Client: response { statements, lock_id, signing_keys }
deactivate WalletD
sequenceDiagram
participant App as Application
participant ConfApi as ConfidentialTransferApi
participant TxApi as TransactionApi
participant Store as Wallet Store
App->>ConfApi: confidential_transfer(seal_signer, lock_ids, ...)
activate ConfApi
ConfApi->>ConfApi: resolve inputs using UtxoInputSelection
ConfApi->>TxApi: locks_set_transaction_id(lock_id, tx_id)
activate TxApi
TxApi->>Store: link lock -> tx
Store-->>TxApi: OK
deactivate TxApi
ConfApi-->>App: result
deactivate ConfApi
sequenceDiagram
participant Client as Indexer Client
participant REST as Indexer REST
participant SubMgr as SubstateManager
participant DB as SQLite Reader
Client->>REST: GET /utxos?resource_address=...&limit=...&from_id=...
activate REST
REST->>SubMgr: list_utxos(resource_address, from_id, limit)
activate SubMgr
SubMgr->>DB: utxos_list(resource_address, from_id, limit)
activate DB
DB-->>SubMgr: Vec<(UtxoId, Utxo)>
deactivate DB
SubMgr-->>REST: ListUtxosResponse{utxos}
REST-->>Client: 200 { utxos: [...] }
deactivate SubMgr
deactivate REST
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–75 minutes Areas needing extra attention:
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 16
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
crates/epoch_oracles/src/configured/real_time_ticker.rs (3)
91-103: Recomputecalculated_epochon every tick; current code can hang whenstart_epoch > calculated_epoch.
calculated_epochis computed once before the loop and never updated. Ifself.epoch > calculated_epoch, the condition never becomes true andpoll_ticknever returns. This breaks the new “base time in future” case.Apply this focused diff:
loop { // Every tick, check if we need to emit a new epoch ready!(interval_mut.poll_tick(cx)); - - if self.epoch <= calculated_epoch { + // Recompute against current time each tick + let calculated_epoch = self.calc_current_epoch(); + if self.epoch <= calculated_epoch { let epoch = self.increment_epoch(); let epoch_hash = calc_static_epoch_hash(epoch); return Poll::Ready(Some(EpochTickerData { epoch, epoch_hash, done_for_now: true, })); } }
111-116: Compile fix: qualifysize_of(not in prelude).Without an import,
size_ofwon’t resolve.- const U64_SIZE: usize = size_of::<u64>(); + const U64_SIZE: usize = std::mem::size_of::<u64>();Optional: avoid
constifFixedHash::byte_size()isn’tconst fn:- const HASH_SIZE: usize = FixedHash::byte_size(); - let mut epoch_hash = [0u8; HASH_SIZE]; - epoch_hash[HASH_SIZE - U64_SIZE..].copy_from_slice(&epoch.to_be_bytes()); + let hash_size = FixedHash::byte_size(); + let mut epoch_hash = [0u8; 32]; // or [0u8; hash_size] if const-evaluable + epoch_hash[hash_size - U64_SIZE..].copy_from_slice(&epoch.to_be_bytes());
105-108: ReturnPoll::Ready(None)to signal stream termination when ticks are disabled.The
EpochTickertrait is designed to support stream termination viaPoll::Ready(None), as demonstrated by theWatchEpochTickerimplementation and its test expectingNoneafter completion. The oracle caller already handles this case correctly (oracle.rs:198–202). ReturningPoll::Pendingwithout registering a waker violates the polling contract and causes a deadlock when ticks are disabled.- // Ticks have been disabled, never return any new epochs - assert!(self.interval.is_none(), "If interval is Some, we should not reach here"); - Poll::Pending + // Ticks disabled: terminate stream + debug_assert!(self.interval.is_none(), "If interval is Some, we should not reach here"); + Poll::Ready(None)integration_tests/tests/steps/wallet_daemon.rs (1)
211-213: Fix logging placeholder (currently prints literal “{public_key}”).Use format! to include the key value.
- cucumber_log("Burning funds using claim key {public_key}"); + cucumber_log(format!("Burning funds using claim key {}", public_key));crates/wallet/sdk/src/apis/stealth_transfer/api.rs (1)
235-246: Bug: lock_id shadowing creates a new lock and leaks the caller’s lock.PreferConfidential creates a fresh lock_id instead of using the provided one. The caller will attempt to release the original lock_id, leaving these new locks orphaned. Use the passed lock_id.
- UtxoInputSelection::PreferConfidential => { - let lock_id = self.outputs_api.create_lock()?; - let (inputs, blinded_amount_locked) = self.outputs_api.lock_outputs_until_partial_amount( + UtxoInputSelection::PreferConfidential => { + let (inputs, blinded_amount_locked) = self.outputs_api.lock_outputs_until_partial_amount( owner_account_component_address, &resource_address, spend_amount, - lock_id, + lock_id, )?;crates/wallet/sdk/src/apis/confidential_transfer.rs (1)
286-299: Lock leak on error path — release lock before returning Err.When resolved_inputs_for_transfer fails, the lock_id created just before it is never released. Release it before returning.
let inputs_to_spend = match self.resolved_inputs_for_transfer( lock_id, params.from_account, params.resource_address, params.amount, params.input_selection, ) { Ok(inputs) => inputs, Err(e) => { - warn!(target: LOG_TARGET, "Unlocking fee fund locks after error: {}", e); - return Err(e); + warn!(target: LOG_TARGET, "Unlocking input locks after error: {}", e); + if let Err(err) = self.confidential_outputs_api.release_lock(lock_id) { + error!(target: LOG_TARGET, "Failed to release lock after error: {}", err); + } + return Err(e); }, };applications/tari_walletd/src/handlers/transaction.rs (1)
252-260: Bug: dry-run signs with Account branch regardless of requesthandle_submit_dry_run always uses KeyBranch::Account even if req.seal_signer specifies a different branch. This will fail for Nonce/other branches.
Apply:
- let transaction = sdk - .local_signer_api() - .sign(KeyBranch::Account, key.key_id, transaction)?; + let transaction = sdk + .local_signer_api() + .sign(req.seal_signer.branch, req.seal_signer.key_id, transaction)?;clients/wallet_daemon_client/src/types.rs (1)
1183-1189: Update DecryptUtxoBalance.tsx: maximum_expected_value cannot be nullThe breaking change is confirmed—
maximum_expected_valueis now required (non-optional). However,applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx:48incorrectly assignsnullwhenformState.maximumExpectedValueis falsy. This violates the type constraint; either provide a sensible default or require the field in the form.
🧹 Nitpick comments (35)
applications/tari_walletd/src/handlers/helpers.rs (1)
150-152: LGTM! Improved error specificity.The change to use
.optional()?.ok_or_else(|| not_found(...))provides clearer, more actionable error messages when an account is not found. This pattern correctly distinguishes between "not found" cases and genuine errors, improving the API's usability.Optional style nitpick: The trailing comma in the
format!macro on line 152 is valid but unconventional:- result = get_account(a, accounts_api) - .optional()? - .ok_or_else(|| not_found(format!("Account '{a}' not found.",)))?; + result = get_account(a, accounts_api) + .optional()? + .ok_or_else(|| not_found(format!("Account '{a}' not found.")))?;crates/engine_types/src/crypto/elgamal.rs (1)
232-232: Consider debug level or summary logging for batch operations.Logging every found balance at info level may generate excessive log volume during batch operations, especially with the new traffic-sim utility.
Consider one of these alternatives:
Option 1: Use debug level for individual items
- info!(target: LOG_TARGET, "Found encrypted balance: {}", v); + debug!(target: LOG_TARGET, "Found encrypted balance: {}", v);Option 2: Add a summary log after the loop completes
} + + let found_count = results.iter().filter(|r| r.is_some()).count(); + info!(target: LOG_TARGET, "Found {}/{} encrypted balances", found_count, results.len()); Ok(results)applications/tari_walletd/src/handlers/stealth_utxos.rs (1)
60-60: Consider extracting helper functions to reduce function length.The function is quite long (128 lines). While the linear flow makes it readable, extracting the file-based and in-memory lookup logic into separate helper functions could improve maintainability.
For example, you could extract:
spawn_file_based_lookup(...)for lines 112-146spawn_in_memory_lookup(...)for lines 153-161+async fn spawn_file_based_lookup( + sdk: WalletSdk, + path: PathBuf, + view_key: ViewKey, + elgamal_proofs: Vec<_>, + value_range: RangeInclusive<u64>, +) -> JoinHandle<anyhow::Result<Vec<u64>>> { + spawn_blocking(move || { + let mut file = fs::File::open(&path) + .map_err(|e| anyhow!("Unable to load value lookup file '{}': {e}", path.display()))?; + let mut lookup = IoReaderValueLookup::load(&mut file)?; + info!( + target: LOG_TARGET, + "Using value lookup table from file '{}' ({}-{}) for brute force balance lookup", + path.display(), + lookup.range().start(), + lookup.range().end() + ); + + let start = value_range.start(); + let end = value_range.end(); + if start < lookup.range().start() || end > lookup.range().end() { + warn!( + target: LOG_TARGET, + "The requested value range ({}-{}) is outside the loaded value lookup table range ({}-{}). \ + This query may take excessive amount of time.", + start, + end, + lookup.range().start(), + lookup.range().end() + ); + } + + sdk.viewable_balance_api().try_brute_force_commitment_balances( + &view_key.key, + elgamal_proofs.iter(), + value_range, + &mut lookup, + ) + }) +}crates/template_lib/src/models/stealth.rs (3)
33-42: Guard against negative revealed output amountsAdd a simple non-negative check to match inputs-side validation and avoid constructing invalid statements.
Apply:
impl StealthOutputsStatement { /// Create a new output statement with no stealth outputs, only a revealed amount. pub fn new_revealed_only(amount: Amount) -> Self { + assert!(!amount.is_negative(), "Revealed output amount must be non-negative"); Self { outputs: vec![], revealed_output_amount: amount, agg_range_proof: RangeProofBytes::empty(), } } }
95-97: Optional balance_proof: consider eliding nulls in JSONIf these structs are serialized to JSON anywhere, add serde skip to avoid emitting explicit nulls; wire format (borsh/proto) unaffected.
Apply:
- #[cfg_attr(feature = "ts", ts(type = "{public_nonce: string, signature: string} | null"))] - pub balance_proof: Option<BalanceProofSignature>, + #[cfg_attr(feature = "ts", ts(type = "{public_nonce: string, signature: string} | null"))] + #[serde(skip_serializing_if = "Option::is_none")] + pub balance_proof: Option<BalanceProofSignature>,
101-111: Assert the “revealed-only” invariant locallyAdd a debug assertion to ensure this constructor never sneaks in stealth I/O and keeps balance_proof None only in that case.
Apply:
pub fn revealed_only( input_amount: Amount, output_amount: Amount, required_signer: RistrettoPublicKeyBytes, ) -> Self { - Self { - inputs_statement: StealthInputsStatement::new_revealed_only(input_amount, required_signer), - outputs_statement: StealthOutputsStatement::new_revealed_only(output_amount), - balance_proof: None, - } + let inputs_statement = StealthInputsStatement::new_revealed_only(input_amount, required_signer); + let outputs_statement = StealthOutputsStatement::new_revealed_only(output_amount); + debug_assert!( + inputs_statement.inputs.is_empty() && outputs_statement.outputs.is_empty(), + "revealed_only must have no stealth inputs/outputs" + ); + Self { + inputs_statement, + outputs_statement, + balance_proof: None, + } }Also, the struct docstrings above still say “must contain confidential outputs”; please update to reflect revealed-only allowance.
crates/p2p/src/conversions/transaction.rs (1)
823-824: Add a debug invariant on serialization symmetryEnsure we never serialize a stealth transfer with missing proof unless it’s revealed-only.
Apply:
impl From<tari_template_lib::models::StealthTransferStatement> for proto::transaction::StealthTransferStatement { fn from(value: tari_template_lib::models::StealthTransferStatement) -> Self { + let is_revealed_only = + value.inputs_statement.inputs.is_empty() && value.outputs_statement.outputs.is_empty(); + let balance_proof_bytes = value.balance_proof.as_ref().map(|b| b.to_bytes()).unwrap_or_default(); + debug_assert!( + (is_revealed_only && balance_proof_bytes.is_empty()) || + (!is_revealed_only && !balance_proof_bytes.is_empty()), + "Invariant: balance_proof must be present unless revealed-only" + ); Self { inputs_statement: Some(value.inputs_statement.into()), outputs_statement: Some(value.outputs_statement.into()), - balance_proof: value.balance_proof.as_ref().map(|b| b.to_bytes()).unwrap_or_default(), + balance_proof: balance_proof_bytes, } } }crates/epoch_oracles/src/configured/real_time_ticker.rs (2)
66-75: Gate the “fast-forward to initial epoch” onself.epochtoo.Avoid needless emissions once
self.epochhas already reached/passedinitial_epoch.- if calculated_epoch < self.initial_epoch { + if calculated_epoch < self.initial_epoch && self.epoch < self.initial_epoch { let epoch = self.increment_epoch(); let epoch_hash = calc_static_epoch_hash(epoch); return Poll::Ready(Some(EpochTickerData { epoch, epoch_hash, done_for_now: false, })); }
164-177: Test relies on loop recompute; will stall without it.With the fix to recompute
calculated_epochper tick, this test should pass. Without it,poll_ticknever returns when base time > now.Consider injecting a clock (trait or
now_fn) intoRealTimeEpochTickerso tests don’t depend on wall-clock timing.utilities/traffic-sim/Cargo.toml (3)
10-11: Relax version pins to caret for compatibility.Use caret constraints to pick up compatible bugfixes without manual bumps.
-clap = { version = "4.0", features = ["derive"] } -tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] } +clap = { version = "4", features = ["derive"] } +tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
15-15: Prefer rustls and disable reqwest default features.Avoid platform OpenSSL issues and shrink dependency tree.
-reqwest = { workspace = true, features = ["json"] } +reqwest = { workspace = true, default-features = false, features = ["json", "rustls-tls"] }If the workspace sets reqwest TLS features globally, confirm no duplication/conflict.
19-19: Avoid hard pin on csv unless strictly required.Use caret for patch updates; keeps reproducible yet flexible.
-csv = "1.4.0" +csv = "1.4"applications/tari_wallet_cli/src/command/transaction.rs (4)
253-256: Improve error context for missing owner key.Include the fee account address to speed up debugging.
- let owner_key_id = fee_account - .owner_key_id - .ok_or_else(|| anyhow!("Fee account does not have an owner key ID"))?; + let owner_key_id = fee_account + .owner_key_id + .ok_or_else(|| anyhow!("Fee account {} does not have an owner key ID", fee_account.component_address))?;
285-291: LGTM – explicit seal_signer and detect_inputs flags are correct.Consider factoring common request fields to reduce duplication between dry-run and submit.
Also applies to: 297-302, 355-360, 366-371
325-328: Apply the same improved error context in manifest submit.Mirror the enhanced message here for consistency.
- let owner_key_id = fee_account - .owner_key_id - .ok_or_else(|| anyhow!("Fee account does not have an owner key ID"))?; + let owner_key_id = fee_account + .owner_key_id + .ok_or_else(|| anyhow!("Fee account {} does not have an owner key ID", fee_account.component_address))?;
445-445: Make input selection configurable.Defaulting to
PreferConfidentialis fine, but expose a CLI flag to toggle selection for ops/debug.Would you like me to add
--input-selection {PreferRevealed|PreferConfidential|RevealedOnly|ConfidentialOnly}? I can wire it with clap and map toUtxoInputSelection.crates/wallet/sdk/src/apis/stealth_transfer/error.rs (1)
5-5: LGTM – error context improved with Amounts.Consider adding serde derives if this bubbles over API boundaries.
crates/wallet/sdk/src/apis/stealth_transfer/params.rs (1)
22-24: Clarify field-level documentation.The comments on lines 22 and 23 are identical. Consider clarifying the distinction between
fee_input_selection(for fee payment) andinput_selection(for main transfer amounts) to improve code maintainability.Apply this diff to improve the documentation:
- /// Strategy for input selection pub fee_input_selection: UtxoInputSelection, - /// Strategy for input selection + /// Strategy for selecting inputs for the fee payment + pub fee_input_selection: UtxoInputSelection, + /// Strategy for selecting inputs for the transfer amount pub input_selection: UtxoInputSelection,utilities/traffic-sim/src/sim.rs (2)
268-412: Consider refactoring for maintainability.This function is 144 lines long and handles multiple concerns (checking balances, creating test coins, creating transfer statements, building transactions, submitting, and waiting for results). Consider extracting smaller helper methods for each major step to improve readability and testability.
286-286: Consider parameterizing the fund amount.The fund amount is hardcoded to
10_000_000_000. Consider making this a parameter to the function for flexibility in different testing scenarios.crates/wallet/sdk/src/apis/stealth_outputs.rs (1)
182-186: New create_lock API: useful, but consider RAII guard to avoid leaked locks on early returns.Expose a small drop-guard (e.g., WalletLockDropGuard) that auto-releases if not finalized, and return it from create_lock to make flows exception-safe.
- pub fn create_lock(&self) -> Result<WalletLockId, StealthOutputsApiError> { - let lock_id = self.store.with_write_tx(|tx| tx.locks_create())?; - Ok(lock_id) - } + pub fn create_lock(&self) -> Result<WalletLockDropGuard<'_, TStore>, StealthOutputsApiError> { + let lock_id = self.store.with_write_tx(|tx| tx.locks_create())?; + Ok(WalletLockDropGuard::new(self.store, lock_id)) + }Note: adjust call sites and provide finalize() to consume the guard.
applications/tari_indexer/src/rest_api/handlers/utxos.rs (2)
100-113: fetch_utxos migration looks correct; keep limit guard consistent with GET list.The 1000 cap mirrors other handlers; consider extracting a shared const to avoid drift.
- if req.tag_and_nonce_pairs.len() > 1000 { + const MAX_UTXO_BATCH: usize = 1000; + if req.tag_and_nonce_pairs.len() > MAX_UTXO_BATCH { return Err(ErrorResponse::bad_request("cannot query more than 1000 UTXOs")); }
115-132: New list_utxos endpoint: solid; unify limits via a shared constant.Add a MAX_UTXO_PAGE_SIZE const and reuse across stream/fetch/list to prevent divergence.
-#[utoipa::path(get, path = "/utxos", description = "List full UTXO data")] +const MAX_UTXO_PAGE_SIZE: u32 = 1000; +#[utoipa::path(get, path = "/utxos", description = "List full UTXO data")] pub async fn list_utxos( Extension(context): Extension<HandlerContext>, Query(req): Query<ListUtxosRequest>, ) -> HandlerResult<Json<ListUtxosResponse>> { - if req.limit == 0 { + if req.limit == 0 { return Err(ErrorResponse::bad_request("limit must be greater than 0")); } - if req.limit > 1000 { + if req.limit > MAX_UTXO_PAGE_SIZE { return Err(ErrorResponse::bad_request("cannot query more than 1000 UTXOs")); }Please confirm the store layer enforces resource scoping with from_id to prevent cross-resource leakage when a malformed from_id is provided.
integration_tests/tests/steps/wallet_daemon.rs (1)
128-135: Improve owner_key_id error message with account context.The suggestion is valid and beneficial. The
owner_key_id()method returnsOption<KeyId>, which can beNoneeven for valid accounts. While the account existence is already guarded at lines 111–114, a panic with the account name will aid debugging. Sinceaccount_nameis available as a function parameter (line 106), the suggested refactor usingunwrap_or_else()with context is an improvement over the generic error message.- seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id().expect("no owner key id")), + seal_signer: BranchAndKeyId::new( + KeyBranch::Account, + account + .owner_key_id() + .unwrap_or_else(|| panic!("Account {account_name} has no owner key id; cannot seal-sign")), + ),utilities/generate_ristretto_value_lookup/src/main.rs (3)
115-117: Scratch-pad preallocation is ineffectivevec![Some(Vec::with_capacity(...)); num_threads] clones an empty Vec; clones lose the reserved capacity. Build each entry explicitly.
- let mut scratch_pad = vec![Some(Vec::with_capacity(CHUNK_SIZE)); num_threads]; + let mut scratch_pad: Vec<Option<Vec<[u8; 32]>>> = + (0..num_threads).map(|_| Some(Vec::with_capacity(CHUNK_SIZE))).collect();
148-153: Buffered writes for throughputWriting 32 bytes per key is syscall-heavy. Wrap the file in a BufWriter with a large buffer.
Within main (near file creation):
-use std::{ - fs, - io, - io::{stdout, Write}, - time::{Duration, Instant}, -}; +use std::{ + fs, + io, + io::{stdout, Write, BufWriter}, + time::{Duration, Instant}, +}; ... - let writer = fs::File::create(&dest_file)?; + let writer = BufWriter::with_capacity(1 << 20, fs::File::create(&dest_file)?); // 1 MiB bufferNo change needed to write_output_async signature since BufWriter implements Write.
18-18: Remove unused importValueLookupTable isn’t used.
-use tari_ootle_wallet_crypto::ValueLookupTable;clients/tari_indexer_client/src/rest_api_client.rs (1)
170-176: get_utxos/list_utxos methods — LGTMPOST to utxos/fetch and GET to utxos are correct and consistent with handlers. Consider surfacing a helper to clamp client-side limit to 1000 to fail fast, but server validates already.
crates/wallet/sdk/src/models/lock_guard.rs (1)
11-14: Guard owns the store; disarm drops it — add must_use and a way to recover the store.Owning TStore means callers lose it once passed in; disarm() also discards it. Add #[must_use] to the guard and expose into_inner() so callers can reclaim the store when disarming.
- pub struct WalletLockDropGuard<TStore: WriteableWalletStore> { + #[must_use] + pub struct WalletLockDropGuard<TStore: WriteableWalletStore> { @@ impl<TStore> WalletLockDropGuard<TStore> where TStore: WriteableWalletStore { @@ pub fn disarm(mut self) { self.store = None; } + + /// Consume the guard and recover the owned store without unlocking. + pub fn into_inner(mut self) -> Option<TStore> { + self.store.take() + } }Also applies to: 30-33
crates/wallet/sdk/src/apis/stealth_transfer/api.rs (1)
135-141: Error variant naming consistency (optional).RevealedOnly returns InsufficientFunds with revealed-specific details, while other branches sometimes use InsufficientRevealedFunds. Consider standardizing the variant for clearer UX.
crates/wallet/sdk/src/apis/confidential_transfer.rs (1)
131-141: Use available_revealed_funds to avoid locking already-reserved funds.PreferRevealed uses src_vault.revealed_balance rather than the computed available_revealed_funds; this can over-request and fail later. Use the available figure.
- UtxoInputSelection::PreferRevealed => { - let revealed_to_spend = cmp::min(src_vault.revealed_balance, spend_amount); + UtxoInputSelection::PreferRevealed => { + let revealed_to_spend = cmp::min(available_revealed_funds, spend_amount);applications/tari_walletd/src/handlers/accounts.rs (3)
1083-1088: Avoid magic number for batch sizeReplace hard-coded 16 with a named constant for clarity and central control.
Apply:
- if req.requests.len() > 16 { + const MAX_STEALTH_STATEMENT_REQUESTS: usize = 16; + if req.requests.len() > MAX_STEALTH_STATEMENT_REQUESTS {If you prefer, hoist the constant near the top of the file.
1168-1179: Deterministic ordering for signing_keysHashSet iteration order is nondeterministic. For stable client UX and reproducible responses, preserve insertion order.
Option A (preferred): use IndexSet.
- let mut required_signers = HashSet::new(); + use indexmap::IndexSet; + let mut required_signers = IndexSet::new(); ... - Ok(AccountsCreateStealthTransferStatementResponse { - statements, - lock_id, - signing_keys: required_signers.into_iter().collect(), - }) + Ok(AccountsCreateStealthTransferStatementResponse { + statements, + lock_id, + signing_keys: required_signers.into_iter().collect(), // now deterministic + })Option B: collect to Vec and sort by (branch, key_id).
1094-1096: Avoid shadowingreqinside the loopShadowing the outer request parameter with
for req in req.requestsharms readability.Rename the loop variable, e.g.:
- for req in req.requests { + for stm_req in req.requests {clients/wallet_daemon_client/src/types.rs (1)
118-134: TransactionSubmitRequest surface looks correctseal_signer/other_signers/lock_ids fields reflect server changes. Consider TS hint for lock_ids if WalletLockId is not already mapped to number[] in TS.
If needed, annotate:
pub struct TransactionSubmitRequest { pub transaction: UnsignedTransaction, pub seal_signer: BranchAndKeyId, pub other_signers: Vec<BranchAndKeyId>, @@ - pub lock_ids: Vec<WalletLockId>, + #[cfg_attr(feature = "ts", ts(type = "Array<number>"))] + pub lock_ids: Vec<WalletLockId>, }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (87)
Cargo.toml(2 hunks)applications/tari_indexer/src/rest_api/handlers/utxos.rs(3 hunks)applications/tari_indexer/src/rest_api/server.rs(2 hunks)applications/tari_indexer/src/storage_sqlite/reader.rs(2 hunks)applications/tari_indexer/src/store.rs(1 hunks)applications/tari_indexer/src/substate_manager.rs(1 hunks)applications/tari_validator_node/src/cli.rs(2 hunks)applications/tari_wallet_cli/src/command/transaction.rs(6 hunks)applications/tari_walletd/src/handlers/accounts.rs(7 hunks)applications/tari_walletd/src/handlers/helpers.rs(1 hunks)applications/tari_walletd/src/handlers/stealth_utxos.rs(5 hunks)applications/tari_walletd/src/handlers/transaction.rs(9 hunks)applications/tari_walletd/src/jrpc_server.rs(1 hunks)applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx(3 hunks)applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx(2 hunks)applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx(3 hunks)applications/tari_walletd/web_ui/src/routes/Transactions/Inputs.tsx(2 hunks)applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts(3 hunks)applications/tari_walletd/web_ui/src/utils/json_rpc.ts(2 hunks)bindings/package.json(1 hunks)bindings/src/index.ts(1 hunks)bindings/src/tari-indexer-client.ts(2 hunks)bindings/src/types/ConfidentialTransferInputSelection.ts(0 hunks)bindings/src/types/StealthTransferStatement.ts(1 hunks)bindings/src/types/UtxoInputSelection.ts(1 hunks)bindings/src/types/tari-indexer-client/GetUtxosRequest.ts(1 hunks)bindings/src/types/tari-indexer-client/GetUtxosResponse.ts(1 hunks)bindings/src/types/tari-indexer-client/ListUtxosRequest.ts(1 hunks)bindings/src/types/tari-indexer-client/ListUtxosResponse.ts(1 hunks)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts(1 hunks)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts(1 hunks)bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/InputSelection.ts(1 hunks)bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts(1 hunks)bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts(0 hunks)bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/TransferOutput.ts(1 hunks)bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts(1 hunks)bindings/src/wallet-daemon-client.ts(4 hunks)clients/javascript/indexer_client/package.json(1 hunks)clients/javascript/wallet_daemon_client/package.json(1 hunks)clients/javascript/wallet_daemon_client/src/index.ts(1 hunks)clients/tari_indexer_client/src/rest_api_client.rs(2 hunks)clients/tari_indexer_client/src/types.rs(1 hunks)clients/wallet_daemon_client/src/component_address.rs(1 hunks)clients/wallet_daemon_client/src/lib.rs(3 hunks)clients/wallet_daemon_client/src/types.rs(7 hunks)crates/engine_types/src/crypto/elgamal.rs(3 hunks)crates/engine_types/src/stealth/transfer.rs(5 hunks)crates/epoch_oracles/src/base_layer/mod.rs(1 hunks)crates/epoch_oracles/src/configured/real_time_ticker.rs(4 hunks)crates/p2p/src/conversions/transaction.rs(2 hunks)crates/template_builtin/templates/faucet/src/lib.rs(1 hunks)crates/template_lib/src/models/stealth.rs(2 hunks)crates/template_test_tooling/src/support/stealth.rs(1 hunks)crates/transaction/src/v1/unsigned.rs(2 hunks)crates/wallet/crypto/src/stealth.rs(3 hunks)crates/wallet/crypto/src/value_lookup/header.rs(1 hunks)crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs(3 hunks)crates/wallet/crypto/src/value_lookup/mod.rs(1 hunks)crates/wallet/crypto/tests/stealth_transfer_statement.rs(8 hunks)crates/wallet/sdk/src/apis/confidential_outputs.rs(0 hunks)crates/wallet/sdk/src/apis/confidential_transfer.rs(13 hunks)crates/wallet/sdk/src/apis/stealth_crypto.rs(1 hunks)crates/wallet/sdk/src/apis/stealth_outputs.rs(5 hunks)crates/wallet/sdk/src/apis/stealth_transfer/api.rs(9 hunks)crates/wallet/sdk/src/apis/stealth_transfer/error.rs(2 hunks)crates/wallet/sdk/src/apis/stealth_transfer/params.rs(2 hunks)crates/wallet/sdk/src/apis/substate.rs(1 hunks)crates/wallet/sdk/src/models/account.rs(1 hunks)crates/wallet/sdk/src/models/key.rs(1 hunks)crates/wallet/sdk/src/models/lock_guard.rs(1 hunks)crates/wallet/sdk/src/models/mod.rs(2 hunks)crates/wallet/sdk/src/models/wallet_transaction.rs(1 hunks)crates/wallet/sdk/src/sdk.rs(1 hunks)crates/wallet/sdk_services/src/indexer_rest_api.rs(2 hunks)integration_tests/src/wallet_daemon_client.rs(10 hunks)integration_tests/tests/steps/wallet_daemon.rs(2 hunks)utilities/generate_ristretto_value_lookup/Cargo.toml(1 hunks)utilities/generate_ristretto_value_lookup/src/cli.rs(1 hunks)utilities/generate_ristretto_value_lookup/src/main.rs(1 hunks)utilities/traffic-sim/Cargo.toml(1 hunks)utilities/traffic-sim/src/main.rs(1 hunks)utilities/traffic-sim/src/sim.rs(1 hunks)
💤 Files with no reviewable changes (3)
- bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts
- crates/wallet/sdk/src/apis/confidential_outputs.rs
- bindings/src/types/ConfidentialTransferInputSelection.ts
🧰 Additional context used
🧬 Code graph analysis (56)
crates/wallet/sdk/src/models/wallet_transaction.rs (1)
bindings/src/types/TransactionStatus.ts (1)
TransactionStatus(3-11)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (2)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)bindings/src/types/wallet-daemon-client/KeyId.ts (1)
KeyId(3-3)
applications/tari_walletd/web_ui/src/utils/json_rpc.ts (3)
clients/javascript/wallet_daemon_client/src/index.ts (1)
submitTransactionDryRun(228-230)bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
TransactionSubmitRequest(5-21)bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunResponse.ts (1)
TransactionSubmitDryRunResponse(5-5)
clients/wallet_daemon_client/src/component_address.rs (1)
bindings/src/types/wallet-daemon-client/ComponentAddressOrName.ts (1)
ComponentAddressOrName(4-4)
crates/wallet/crypto/src/stealth.rs (2)
crates/engine_types/src/crypto/messages.rs (1)
stealth_statement_metadata64(74-79)crates/wallet/crypto/src/balance_proof.rs (1)
generate_stealth_balance_proof_signature(38-55)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (4)
bindings/src/types/wallet-daemon-client/ComponentAddressOrName.ts (1)
ComponentAddressOrName(4-4)bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/wallet-daemon-client/InputSelection.ts (1)
InputSelection(5-5)bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
TransferOutput(6-24)
crates/wallet/sdk/src/models/account.rs (3)
crates/wallet/sdk/src/models/key.rs (1)
new(294-296)bindings/src/types/Account.ts (1)
Account(6-14)bindings/src/types/OotleAddress.ts (1)
OotleAddress(3-3)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)
crates/template_lib/src/models/stealth.rs (4)
crates/state_store_rocksdb/src/codecs/small_bytes.rs (1)
empty(19-21)bindings/src/types/StealthTransferStatement.ts (1)
StealthTransferStatement(5-13)bindings/src/types/RistrettoPublicKeyBytes.ts (1)
RistrettoPublicKeyBytes(6-6)bindings/src/types/StealthInputsStatement.ts (1)
StealthInputsStatement(9-22)
bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (2)
bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)bindings/src/types/Utxo.ts (1)
Utxo(4-4)
bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (2)
bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)bindings/src/types/Utxo.ts (1)
Utxo(4-4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
TransferStatementRequest(7-12)
applications/tari_indexer/src/store.rs (1)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
utxos_list(563-606)
applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (2)
crates/engine_types/src/resource.rs (1)
divisibility(211-213)applications/tari_walletd/web_ui/src/utils/helpers.tsx (1)
bigintToDecimalString(233-253)
applications/tari_walletd/src/handlers/helpers.rs (1)
crates/wallet/sdk/src/sdk.rs (1)
accounts_api(228-235)
crates/wallet/sdk/src/models/key.rs (3)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)bindings/src/types/wallet-daemon-client/KeyId.ts (1)
KeyId(3-3)
applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (2)
bindings/src/types/StealthTransferStatement.ts (1)
StealthTransferStatement(5-13)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (2)
bindings/src/types/OotleAddress.ts (1)
OotleAddress(3-3)bindings/src/types/Amount.ts (1)
Amount(12-12)
applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (2)
bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)bindings/src/helpers/consts.ts (1)
XTR(10-10)
bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts (2)
bindings/src/types/Amount.ts (1)
Amount(12-12)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
applications/tari_wallet_cli/src/command/transaction.rs (6)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)crates/wallet/sdk/src/models/account.rs (2)
owner_key_id(33-35)owner_key_id(95-97)crates/wallet/sdk/src/models/key.rs (1)
for_account(298-303)bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
TransactionSubmitRequest(5-21)
applications/tari_walletd/src/handlers/stealth_utxos.rs (5)
applications/tari_walletd/src/handlers/helpers.rs (1)
invalid_params(162-173)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
StealthUtxosDecryptValueRequest(5-11)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
StealthUtxosDecryptValueResponse(4-4)crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (3)
lookup(90-101)load(26-35)range(82-84)crates/wallet/crypto/src/value_lookup/mod.rs (1)
lookup(19-21)
utilities/generate_ristretto_value_lookup/src/main.rs (3)
utilities/generate_ristretto_value_lookup/src/cli.rs (1)
init(31-33)crates/engine_types/src/crypto/elgamal.rs (3)
lookup(293-298)from(160-162)from(166-171)crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (2)
lookup(90-101)load(26-35)
bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (2)
bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)
applications/tari_walletd/src/jrpc_server.rs (2)
applications/tari_swarm_daemon/src/webserver/server.rs (1)
call_handler(154-178)applications/tari_walletd/src/handlers/accounts.rs (2)
accounts(258-267)handle_create_stealth_transfer_statement(1069-1180)
utilities/traffic-sim/src/sim.rs (5)
clients/tari_indexer_client/src/rest_api_client.rs (1)
connect(53-66)clients/wallet_daemon_client/src/lib.rs (2)
connect(149-164)endpoint(166-168)clients/wallet_daemon_client/src/component_address.rs (5)
name(21-26)component_address(28-33)from(58-60)from(64-66)from(69-71)crates/wallet/sdk/src/models/account.rs (7)
name(41-43)name(87-89)address(83-85)new(71-73)account(75-77)component_address(25-27)component_address(79-81)crates/engine_types/src/resource.rs (2)
divisibility(211-213)token_symbol(207-209)
crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (1)
crates/wallet/crypto/src/value_lookup/header.rs (1)
is_in_range(43-45)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (2)
bindings/src/types/UnsignedTransaction.ts (1)
UnsignedTransaction(4-4)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)
applications/tari_indexer/src/rest_api/server.rs (4)
applications/tari_indexer/src/storage_sqlite/reader.rs (2)
utxos(505-509)utxos(635-640)applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
list_utxos(116-132)applications/tari_indexer/src/substate_manager.rs (1)
list_utxos(143-153)clients/tari_indexer_client/src/rest_api_client.rs (1)
list_utxos(174-176)
crates/wallet/sdk/src/apis/stealth_transfer/params.rs (2)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
clients/javascript/wallet_daemon_client/src/index.ts (2)
bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
TransactionSubmitRequest(5-21)bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunResponse.ts (1)
TransactionSubmitDryRunResponse(5-5)
applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx (1)
bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (7)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
GetUtxosRequest(6-9)bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
GetUtxosResponse(5-5)bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
ListUtxosRequest(5-5)bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
ListUtxosResponse(5-5)applications/tari_indexer/src/storage_sqlite/reader.rs (2)
utxos(505-509)utxos(635-640)applications/tari_indexer/src/substate_manager.rs (1)
list_utxos(143-153)clients/tari_indexer_client/src/rest_api_client.rs (1)
list_utxos(174-176)
crates/engine_types/src/stealth/transfer.rs (1)
crates/engine_types/src/crypto/helpers.rs (1)
try_decode_to_signature(91-93)
applications/tari_indexer/src/substate_manager.rs (2)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
list_utxos(116-132)clients/tari_indexer_client/src/rest_api_client.rs (1)
list_utxos(174-176)
bindings/src/types/wallet-daemon-client/InputSelection.ts (2)
bindings/src/types/Amount.ts (1)
Amount(12-12)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
crates/wallet/crypto/tests/stealth_transfer_statement.rs (2)
crates/wallet/crypto/src/stealth.rs (2)
output_statements(123-153)create_outputs_statement(119-162)crates/wallet/crypto/src/balance_proof.rs (1)
generate_stealth_balance_proof_signature(38-55)
clients/wallet_daemon_client/src/lib.rs (4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)clients/validator_node_client/src/lib.rs (1)
endpoint(58-60)bindings/src/types/wallet-daemon-client/ProofsGenerateRequest.ts (1)
ProofsGenerateRequest(8-15)
integration_tests/tests/steps/wallet_daemon.rs (3)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)crates/wallet/sdk/src/models/key.rs (1)
new(294-296)bindings/src/types/Account.ts (1)
Account(6-14)
applications/tari_validator_node/src/cli.rs (1)
applications/tari_app_utilities/src/configuration.rs (1)
convert_l1_network_to_network(31-40)
applications/tari_walletd/src/handlers/accounts.rs (8)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
TransferOutput(6-24)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)applications/tari_walletd/src/handlers/helpers.rs (3)
get_account(113-124)not_found(183-190)invalid_params(162-173)crates/wallet/sdk/src/apis/stealth_outputs.rs (2)
new(69-81)outputs(692-692)crates/wallet/sdk/src/models/key.rs (1)
new(294-296)crates/wallet/sdk/src/models/lock_guard.rs (1)
lock_id(26-28)
clients/tari_indexer_client/src/rest_api_client.rs (6)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
GetUtxosRequest(6-9)bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
GetUtxosResponse(5-5)bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
ListUtxosRequest(5-5)bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
ListUtxosResponse(5-5)applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
list_utxos(116-132)applications/tari_indexer/src/substate_manager.rs (1)
list_utxos(143-153)
crates/wallet/sdk/src/apis/stealth_transfer/api.rs (2)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
crates/transaction/src/v1/unsigned.rs (4)
bindings/src/helpers/consts.ts (1)
XTR(10-10)bindings/src/types/UtxoAddress.ts (1)
UtxoAddress(4-4)bindings/src/types/Instruction.ts (1)
Instruction(15-42)bindings/src/types/ResourceAddressRef.ts (1)
ResourceAddressRef(5-5)
clients/wallet_daemon_client/src/types.rs (10)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
TransferOutput(6-24)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
TransferStatementRequest(7-12)bindings/src/types/wallet-daemon-client/InputSelection.ts (1)
InputSelection(5-5)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1)
StealthTransferRequest(8-17)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
StealthUtxosDecryptValueResponse(4-4)
utilities/traffic-sim/src/main.rs (2)
utilities/traffic-sim/src/sim.rs (1)
wallets(113-115)clients/wallet_daemon_client/src/lib.rs (1)
endpoint(166-168)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
applications/tari_indexer/src/store.rs (1)
utxos_list(153-158)
integration_tests/src/wallet_daemon_client.rs (7)
bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)bindings/src/types/Account.ts (1)
Account(6-14)bindings/src/types/AccountWithAddress.ts (1)
AccountWithAddress(5-5)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)crates/wallet/sdk/src/models/account.rs (3)
owner_key_id(33-35)owner_key_id(95-97)account(75-77)crates/wallet/sdk/src/models/key.rs (1)
for_account(298-303)
crates/wallet/sdk/src/apis/stealth_transfer/error.rs (2)
bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/Amount.ts (1)
Amount(12-12)
clients/tari_indexer_client/src/types.rs (9)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
GetUtxosRequest(6-9)bindings/src/types/UtxoTag.ts (1)
UtxoTag(8-8)bindings/src/types/RistrettoPublicKeyBytes.ts (1)
RistrettoPublicKeyBytes(6-6)bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
GetUtxosResponse(5-5)bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)bindings/src/types/Utxo.ts (1)
Utxo(4-4)bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
ListUtxosRequest(5-5)bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
ListUtxosResponse(5-5)
crates/wallet/sdk/src/apis/confidential_transfer.rs (3)
crates/wallet/sdk/src/sdk.rs (2)
network(189-191)transaction_api(220-222)crates/wallet/sdk/src/apis/transaction.rs (1)
new(40-45)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
crates/p2p/src/conversions/transaction.rs (1)
crates/template_lib_types/src/crypto/scalar.rs (1)
from_bytes(32-43)
applications/tari_walletd/src/handlers/transaction.rs (5)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)crates/wallet/sdk/src/models/account.rs (2)
owner_key_id(33-35)owner_key_id(95-97)applications/tari_walletd/src/handlers/helpers.rs (1)
invalid_params(162-173)crates/wallet/sdk/src/models/key.rs (1)
for_account(298-303)
crates/wallet/sdk_services/src/indexer_rest_api.rs (1)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
GetUtxosRequest(6-9)
crates/template_test_tooling/src/support/stealth.rs (3)
crates/template_test_tooling/src/support/confidential.rs (1)
inputs(170-176)crates/template_lib/src/models/stealth.rs (1)
revealed_input_amount(113-115)crates/wallet/sdk/src/apis/stealth_outputs.rs (1)
outputs(692-692)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: test
- GitHub Check: check stable
- GitHub Check: check nightly
- GitHub Check: clippy
- GitHub Check: machete
- GitHub Check: fmt
| use tari_common::{ | ||
| configuration::{ConfigOverrideProvider, Network as L1Network}, | ||
| ConfigPath, | ||
| }; | ||
| use tari_ootle_app_utilities::{ | ||
| configuration::convert_l1_network_to_network, | ||
| p2p_config::{PeerSeedsConfig, ReachabilityMode}, | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
Verify if ConfigPath import is necessary.
The ConfigPath import on line 29 doesn't appear to be used anywhere in this file. If it's not needed, consider removing it to keep imports clean.
Run the following script to verify if ConfigPath is used in this file:
🏁 Script executed:
#!/bin/bash
# Description: Check if ConfigPath is used in the cli.rs file
# Search for ConfigPath usage excluding the import line
rg -n 'ConfigPath' applications/tari_validator_node/src/cli.rs | grep -v 'use.*ConfigPath'Length of output: 18
Remove unused ConfigPath import from line 29.
The verification confirms that ConfigPath is imported on line 29 but is never used anywhere in this file. Remove it to keep imports clean.
🤖 Prompt for AI Agents
In applications/tari_validator_node/src/cli.rs around lines 27 to 34, the import
list includes an unused ConfigPath (line 29); remove ConfigPath from the
tari_common import group so the file no longer imports that unused symbol and
keep imports tidy.
7610f95 to
3966133
Compare
d6fad2d to
53db32b
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (10)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
9-10: Breaking change: maximum_expected_value now required, but call sites still pass null.The past review correctly identified that removing nullability from
maximum_expected_valuewhile keepingminimum_expected_valuenullable creates both a type contract violation (DecryptUtxoBalance.tsx line 48 still passesnull) and an unexplained asymmetry with similar types likeConfidentialViewVaultBalanceRequest.Since this is a generated file, the fix must be applied to the Rust source. Given the
feat!:breaking change marker in the PR title, ensure:
- All downstream call sites are updated to provide a concrete value
- The asymmetry between min/max nullability is intentional and documented
- A migration guide addresses this breaking API change
The verification script from the past review remains valid for confirming all call sites have been updated.
clients/wallet_daemon_client/src/types.rs (1)
1194-1194: Field renamed frombalancestovalues- frontend update required.This field rename requires corresponding updates in the TypeScript UI code. As noted in the previous review,
DecryptUtxoBalance.tsxstill accesses.balancesinstead of.values.applications/tari_indexer/src/storage_sqlite/reader.rs (1)
563-606: Burnt UTXOs should also be filtered in utxos_list query.As noted in the previous review, Line 574 currently only filters
is_spent = falsebut should also exclude burnt UTXOs (is_burnt = false) for consistency with other unspent UTXO queries in this file (e.g.,utxos_get_unspent_by_public_nonce_and_tagat lines 638-639).Apply this diff:
let mut query = utxos::table .filter(utxos::resource_address.eq(resource_address.to_string())) .filter(utxos::is_spent.eq(false)) + .filter(utxos::is_burnt.eq(false)) .into_boxed();applications/tari_validator_node/src/cli.rs (1)
27-30: Remove unusedConfigPathimport.
ConfigPathisn’t referenced in this file. Drop it to keep imports clean.-use tari_common::{ - configuration::{ConfigOverrideProvider, Network as L1Network}, - ConfigPath, -}; +use tari_common::configuration::{ConfigOverrideProvider, Network as L1Network};utilities/generate_ristretto_value_lookup/src/main.rs (2)
73-77: Compile risk: tokio runtime metrics require tokio_unstable; use a stable fallback.Replace metrics-based worker count with std::thread::available_parallelism() and ensure at least 1.
Apply:
- let jobs = cli - .jobs - .unwrap_or_else(|| tokio::runtime::Handle::current().metrics().num_workers()); + let jobs = cli.jobs.unwrap_or_else(|| { + std::thread::available_parallelism() + .map(|n| n.get()) + .unwrap_or(1) + });
168-183: Progress denominator off by one in printed total.Total values =
max - min + 1, but the print usesmax - min.Apply:
- "{:.1}% ETA: {}. {}/{} values generated in {}", + "{:.1}% ETA: {}. {}/{} values generated in {}", (completed as f64 / (max - min + 1) as f64) * 100.0, humantime::format_duration(est_time), completed, - max - min, + max - min + 1, humantime::format_duration(Duration::from_secs(elapsed.as_secs()))applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (1)
161-163: Use strict equality for XTR checkChange == to === to avoid type coercion surprises.
- // For simplicity, we'll use prefer revealed for fees whenever a non-XTR stealth transfer is made - fee_input_selection: params.resource_address == XTR ? params.input_selection : "PreferRevealed", + // For simplicity, we'll use PreferRevealed for fees whenever a non‑XTR stealth transfer is made + fee_input_selection: params.resource_address === XTR ? params.input_selection : "PreferRevealed",#!/bin/bash # Verify no other '== XTR' checks remain rg -nP --type=ts -C2 '\b==\s*XTR\b'applications/tari_walletd/src/handlers/accounts.rs (3)
1103-1104: Validate resource is stealth before proceedingStill missing the stealth-type guard. Generate a clear error early to avoid confusing decode failures later.
Apply this diff:
let resource = sdk.substate_api().fetch_resource(req.resource_address).await?; + if !resource.resource_type().is_stealth() { + return Err(invalid_params( + "resource_address", + Some(format!( + "Resource is not a stealth resource (type: {})", + resource.resource_type() + )), + )); + }
1121-1127: Must sign with account key when revealed funds come FromBucket as wellCondition still omits revealed funds provided via FromBucket.
Apply this diff:
- let must_sign_with_account_key = inputs.as_ref().is_some_and(|i| i.revealed.is_positive()); + let must_sign_with_account_key = + inputs.as_ref().is_some_and(|i| i.revealed.is_positive()) || + req.input_selection.as_from_bucket().is_some_and(|a| a.is_positive());
1152-1163: Avoid checked_add_positive with zero addend for input_revealed_amountZero addend causes a spurious error; compute conditionally.
Apply this diff:
- input_revealed_amount: req - .input_selection - .as_from_bucket() - .unwrap_or(Amount::zero()) - .checked_add_positive(inputs.as_ref().map(|i| i.revealed).unwrap_or(Amount::zero())) - .ok_or_else(|| { - invalid_params( - "input_revealed_amount", - Some("input revealed amount overflowed or was negative"), - ) - })?, + input_revealed_amount: { + let mut total = req.input_selection.as_from_bucket().unwrap_or(Amount::zero()); + if let Some(i) = inputs.as_ref() { + if i.revealed.is_positive() { + total = total.checked_add_positive(i.revealed).ok_or_else(|| { + invalid_params( + "input_revealed_amount", + Some("input revealed amount overflowed"), + ) + })?; + } + } + total + },
🧹 Nitpick comments (15)
crates/wallet/sdk/src/models/wallet_transaction.rs (1)
51-57: Add documentation for these public helper methods.These methods are part of the public API but lack doc comments. Consider adding documentation to clarify the distinction between "any acceptance" (including partial fee-only acceptance) and full acceptance.
Apply this diff to add documentation:
+ /// Returns `true` if the transaction has been accepted in any form, + /// including full acceptance or fee-only acceptance. pub fn is_any_accept(&self) -> bool { matches!(self, TransactionStatus::Accepted | TransactionStatus::OnlyFeeAccepted) } + /// Returns `true` only if the transaction has been fully accepted. pub fn is_accepted(&self) -> bool { matches!(self, TransactionStatus::Accepted) }crates/engine_types/src/crypto/elgamal.rs (1)
232-232: Consider debug level for balance discovery logs.The info log at line 232 will fire for each balance found during brute force decryption. If this method is frequently called with large batches, log verbosity could become substantial.
Consider using
debug!instead ofinfo!unless operational visibility at the info level is specifically required. Additionally, verify that logging actual balance values is acceptable from a privacy/security perspective in production environments.Apply this diff to reduce log verbosity:
- info!(target: LOG_TARGET, "Found encrypted balance: {}", v); + debug!(target: LOG_TARGET, "Found encrypted balance: {}", v);applications/tari_wallet_cli/src/command/transaction.rs (1)
253-255: Owner key derivation is correct.The error handling properly guards against missing owner key IDs. However, this exact pattern is duplicated in
handle_submit_manifest(lines 325-327).Consider extracting a helper function to reduce duplication:
async fn get_fee_account_owner_key_id( client: &mut WalletDaemonClient, fee_account_arg: Option<ComponentAddressOrName>, ) -> Result<KeyId, anyhow::Error> { let fee_account = if let Some(fee_account_name) = fee_account_arg { client.accounts_get(fee_account_name).await?.account } else { client.accounts_get_default().await?.account }; fee_account .owner_key_id .ok_or_else(|| anyhow!("Fee account does not have an owner key ID")) }Then use it in both functions:
let owner_key_id = get_fee_account_owner_key_id(client, common.fee_account.clone()).await?;applications/tari_walletd/src/handlers/stealth_utxos.rs (1)
181-181: Consider renaming for consistency.The variable is named
balanceswhile the response field isvalues(line 186). Consider renaming the variable tovaluesfor consistency with the public API.- let balances = handle.await??; + let values = handle.await??;Then update line 186:
- values: proofs.into_keys().zip(balances).collect(), + values: proofs.into_keys().zip(values).collect(),applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (1)
45-45: Good change: Dynamic divisibility with safe fallback.The derivation correctly uses the resource's divisibility property with a safe fallback to 6 when balance data is unavailable. This enables proper formatting for resources with different decimal places.
Optionally, consider adding a comment explaining why 6 is the default (e.g., XTR's divisibility):
+ // Default to 6 (XTR divisibility) when resource balance is unavailable const divisibility = resourceBalance ? resourceBalance.divisibility : 6;crates/engine_types/src/stealth/transfer.rs (1)
59-68: Consider refining the error message phrasing.The security logic is sound — requiring
Nonebalance proof when there are no stealth inputs/outputs prevents leaking the secret nonce. However, the error message ending with "None is required" is slightly awkward.Consider this minor phrasing improvement:
- details: "Balance proof signature verification failed for revealed amount. This indicates that the \ - transfer statement provided a balance proof when there are no stealth inputs or outputs, \ - None is required." + details: "Balance proof must be None when there are no stealth inputs or outputs (providing a proof \ + would leak the secret nonce)."crates/wallet/sdk/src/models/lock_guard.rs (1)
11-33: Consider adding documentation for the public API.The public struct and methods would benefit from doc comments explaining:
- The purpose and usage pattern of the guard
- When and why to call
disarm()- Whether the guard is
Send/Syncand any thread-safety considerationsapplications/tari_validator_node/src/cli.rs (1)
108-116: Extract repeatedpeer_seeds.join()to reduce duplication.The key path format is correct as-is (matches TOML structure:
[nextnet.p2p.seeds], etc.). However, the duplication ofself.peer_seeds.join(",")at lines 111 and 115 should be factored out:if !self.peer_seeds.is_empty() { + let seeds = self.peer_seeds.join(","); overrides.push(( format!("{}.peer_seeds", PeerSeedsConfig::main_key_prefix()), - self.peer_seeds.join(","), + seeds.clone(), )); overrides.push(( format!("{}.{}.peer_seeds", network, PeerSeedsConfig::main_key_prefix()), - self.peer_seeds.join(","), + seeds, )); }Note: The same pattern exists in
applications/tari_indexer/src/cli.rs(lines 101–106) and should be refactored identically.utilities/generate_ristretto_value_lookup/src/main.rs (3)
71-78: Buffer and preallocate the output file to reduce blocking and IO syscalls.Large numbers of 32‑byte writes on a std::fs::File in an async context can block the runtime thread and be slow.
Apply:
- let writer = fs::File::create(&dest_file)?; + let mut file = fs::File::create(&dest_file)?; + // Best-effort preallocation; ignore if filesystem doesn't support it + let _ = file.set_len(file_size as u64); + let writer = std::io::BufWriter::with_capacity(8 * 1024 * 1024, file);
28-37: Speed up validation reads with a buffered reader (optional).Validation iterates the entire file; using BufReader reduces syscalls and wall time.
Apply:
- let mut file = fs::File::open(&dest_file)?; - let mut lookup = tari_ootle_wallet_crypto::IoReaderValueLookup::load(&mut file)?; + let file = fs::File::open(&dest_file)?; + let mut reader = std::io::BufReader::with_capacity(8 * 1024 * 1024, file); + let mut lookup = tari_ootle_wallet_crypto::IoReaderValueLookup::load(&mut reader)?;
95-100: Optional: flush at the end of write_output_async.Be explicit to surface IO errors early.
Add before returning Ok(()):
writer.flush()?;applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (1)
211-213: Preempt UI to avoid runtime throw when owner_key_id is missingGood guard. Consider disabling submit (and surfacing a helper text alongside the account selector) if account.account.owner_key_id is null, rather than throwing at execution time. This avoids user-facing exceptions.
crates/template_lib/src/models/stealth.rs (1)
101-112: Enforce value conservation in revealed-only constructorAdd a simple assert to ensure input_amount equals output_amount for revealed-only statements to prevent accidental mismatches at construction time. Ledger will enforce this later, but failing fast here reduces footguns.
pub fn revealed_only( input_amount: Amount, output_amount: Amount, required_signer: RistrettoPublicKeyBytes, ) -> Self { + assert!( + input_amount == output_amount, + "Revealed-only stealth transfer must conserve value (inputs == outputs)" + ); Self { inputs_statement: StealthInputsStatement::new_revealed_only(input_amount, required_signer), outputs_statement: StealthOutputsStatement::new_revealed_only(output_amount), balance_proof: None, } }applications/tari_walletd/src/handlers/transaction.rs (1)
256-260: Update comment to reflect locks, not proofsComment still references “proofs table”. Please update to “locks”.
- // update the proofs table with the corresponding transaction hash + // update the locks with the corresponding transaction ID for later finalization/releaseapplications/tari_walletd/src/handlers/accounts.rs (1)
1105-1106: Reject zero-output requests earlyGuard against no-op statements to avoid needless locking/work.
Apply this diff:
let amount_to_spend = req.total_output_amount(); + if amount_to_spend.is_zero() { + return Err(invalid_params("outputs", Some("total output amount must be > 0"))); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (87)
Cargo.toml(2 hunks)applications/tari_indexer/src/rest_api/handlers/utxos.rs(3 hunks)applications/tari_indexer/src/rest_api/server.rs(2 hunks)applications/tari_indexer/src/storage_sqlite/reader.rs(2 hunks)applications/tari_indexer/src/store.rs(1 hunks)applications/tari_indexer/src/substate_manager.rs(1 hunks)applications/tari_validator_node/src/cli.rs(2 hunks)applications/tari_wallet_cli/src/command/transaction.rs(6 hunks)applications/tari_walletd/src/handlers/accounts.rs(7 hunks)applications/tari_walletd/src/handlers/helpers.rs(1 hunks)applications/tari_walletd/src/handlers/stealth_utxos.rs(5 hunks)applications/tari_walletd/src/handlers/transaction.rs(9 hunks)applications/tari_walletd/src/jrpc_server.rs(1 hunks)applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx(3 hunks)applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx(2 hunks)applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx(3 hunks)applications/tari_walletd/web_ui/src/routes/Transactions/Inputs.tsx(2 hunks)applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts(3 hunks)applications/tari_walletd/web_ui/src/utils/json_rpc.ts(2 hunks)bindings/package.json(1 hunks)bindings/src/index.ts(1 hunks)bindings/src/tari-indexer-client.ts(2 hunks)bindings/src/types/ConfidentialTransferInputSelection.ts(0 hunks)bindings/src/types/StealthTransferStatement.ts(1 hunks)bindings/src/types/UtxoInputSelection.ts(1 hunks)bindings/src/types/tari-indexer-client/GetUtxosRequest.ts(1 hunks)bindings/src/types/tari-indexer-client/GetUtxosResponse.ts(1 hunks)bindings/src/types/tari-indexer-client/ListUtxosRequest.ts(1 hunks)bindings/src/types/tari-indexer-client/ListUtxosResponse.ts(1 hunks)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts(1 hunks)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts(1 hunks)bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/InputSelection.ts(1 hunks)bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts(1 hunks)bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts(0 hunks)bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts(1 hunks)bindings/src/types/wallet-daemon-client/TransferOutput.ts(1 hunks)bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts(1 hunks)bindings/src/wallet-daemon-client.ts(4 hunks)clients/javascript/indexer_client/package.json(1 hunks)clients/javascript/wallet_daemon_client/package.json(1 hunks)clients/javascript/wallet_daemon_client/src/index.ts(1 hunks)clients/tari_indexer_client/src/rest_api_client.rs(2 hunks)clients/tari_indexer_client/src/types.rs(1 hunks)clients/wallet_daemon_client/src/component_address.rs(1 hunks)clients/wallet_daemon_client/src/lib.rs(3 hunks)clients/wallet_daemon_client/src/types.rs(7 hunks)crates/engine_types/src/crypto/elgamal.rs(3 hunks)crates/engine_types/src/stealth/transfer.rs(5 hunks)crates/epoch_oracles/src/base_layer/mod.rs(1 hunks)crates/epoch_oracles/src/configured/real_time_ticker.rs(4 hunks)crates/p2p/src/conversions/transaction.rs(2 hunks)crates/template_builtin/templates/faucet/src/lib.rs(1 hunks)crates/template_lib/src/models/stealth.rs(2 hunks)crates/template_test_tooling/src/support/stealth.rs(1 hunks)crates/transaction/src/v1/unsigned.rs(2 hunks)crates/wallet/crypto/src/stealth.rs(3 hunks)crates/wallet/crypto/src/value_lookup/header.rs(1 hunks)crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs(3 hunks)crates/wallet/crypto/src/value_lookup/mod.rs(1 hunks)crates/wallet/crypto/tests/stealth_transfer_statement.rs(8 hunks)crates/wallet/sdk/src/apis/confidential_outputs.rs(0 hunks)crates/wallet/sdk/src/apis/confidential_transfer.rs(13 hunks)crates/wallet/sdk/src/apis/stealth_crypto.rs(1 hunks)crates/wallet/sdk/src/apis/stealth_outputs.rs(5 hunks)crates/wallet/sdk/src/apis/stealth_transfer/api.rs(9 hunks)crates/wallet/sdk/src/apis/stealth_transfer/error.rs(2 hunks)crates/wallet/sdk/src/apis/stealth_transfer/params.rs(2 hunks)crates/wallet/sdk/src/apis/substate.rs(1 hunks)crates/wallet/sdk/src/models/account.rs(1 hunks)crates/wallet/sdk/src/models/key.rs(1 hunks)crates/wallet/sdk/src/models/lock_guard.rs(1 hunks)crates/wallet/sdk/src/models/mod.rs(2 hunks)crates/wallet/sdk/src/models/wallet_transaction.rs(1 hunks)crates/wallet/sdk/src/sdk.rs(1 hunks)crates/wallet/sdk_services/src/indexer_rest_api.rs(2 hunks)integration_tests/src/wallet_daemon_client.rs(10 hunks)integration_tests/tests/steps/wallet_daemon.rs(2 hunks)utilities/generate_ristretto_value_lookup/Cargo.toml(1 hunks)utilities/generate_ristretto_value_lookup/src/cli.rs(1 hunks)utilities/generate_ristretto_value_lookup/src/main.rs(1 hunks)utilities/traffic-sim/Cargo.toml(1 hunks)utilities/traffic-sim/src/main.rs(1 hunks)utilities/traffic-sim/src/sim.rs(1 hunks)
💤 Files with no reviewable changes (3)
- crates/wallet/sdk/src/apis/confidential_outputs.rs
- bindings/src/types/wallet-daemon-client/TransactionSubmitDryRunRequest.ts
- bindings/src/types/ConfidentialTransferInputSelection.ts
🚧 Files skipped from review as they are similar to previous changes (44)
- crates/epoch_oracles/src/base_layer/mod.rs
- crates/wallet/sdk/src/models/account.rs
- bindings/src/types/tari-indexer-client/ListUtxosRequest.ts
- clients/javascript/wallet_daemon_client/src/index.ts
- bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts
- crates/epoch_oracles/src/configured/real_time_ticker.rs
- crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs
- crates/wallet/sdk/src/apis/stealth_crypto.rs
- bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts
- applications/tari_walletd/web_ui/src/routes/AssetVault/Tokens/components/SendMoney.tsx
- bindings/src/index.ts
- applications/tari_walletd/web_ui/src/utils/json_rpc.ts
- bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts
- applications/tari_indexer/src/rest_api/server.rs
- bindings/src/types/tari-indexer-client/GetUtxosRequest.ts
- crates/wallet/crypto/src/value_lookup/header.rs
- crates/wallet/sdk/src/apis/stealth_transfer/params.rs
- clients/javascript/wallet_daemon_client/package.json
- crates/transaction/src/v1/unsigned.rs
- bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts
- crates/wallet/crypto/src/value_lookup/mod.rs
- crates/wallet/sdk/src/apis/stealth_outputs.rs
- utilities/generate_ristretto_value_lookup/src/cli.rs
- crates/wallet/sdk/src/apis/substate.rs
- bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts
- clients/javascript/indexer_client/package.json
- bindings/src/types/UtxoInputSelection.ts
- clients/tari_indexer_client/src/types.rs
- clients/wallet_daemon_client/src/component_address.rs
- applications/tari_walletd/web_ui/src/routes/Transactions/Inputs.tsx
- bindings/src/types/tari-indexer-client/ListUtxosResponse.ts
- crates/template_builtin/templates/faucet/src/lib.rs
- bindings/src/types/tari-indexer-client/GetUtxosResponse.ts
- bindings/src/types/StealthTransferStatement.ts
- applications/tari_walletd/src/jrpc_server.rs
- bindings/src/wallet-daemon-client.ts
- bindings/src/types/wallet-daemon-client/InputSelection.ts
- clients/tari_indexer_client/src/rest_api_client.rs
- bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts
- crates/wallet/sdk/src/models/key.rs
- utilities/traffic-sim/Cargo.toml
- integration_tests/tests/steps/wallet_daemon.rs
- bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts
- applications/tari_indexer/src/store.rs
🧰 Additional context used
🧬 Code graph analysis (31)
crates/wallet/sdk/src/models/wallet_transaction.rs (1)
bindings/src/types/TransactionStatus.ts (1)
TransactionStatus(3-11)
applications/tari_walletd/src/handlers/helpers.rs (2)
crates/wallet/sdk/src/sdk.rs (1)
accounts_api(228-235)crates/wallet/sdk/src/storage.rs (1)
not_found(156-158)
crates/wallet/sdk/src/apis/stealth_transfer/error.rs (2)
bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/Amount.ts (1)
Amount(12-12)
utilities/generate_ristretto_value_lookup/src/main.rs (2)
utilities/generate_ristretto_value_lookup/src/cli.rs (1)
init(31-33)crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (2)
lookup(90-101)load(26-35)
clients/wallet_daemon_client/src/lib.rs (4)
bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)clients/validator_node_client/src/lib.rs (1)
endpoint(58-60)bindings/src/types/wallet-daemon-client/ProofsGenerateRequest.ts (1)
ProofsGenerateRequest(8-15)
applications/tari_validator_node/src/cli.rs (1)
applications/tari_app_utilities/src/configuration.rs (1)
convert_l1_network_to_network(31-40)
applications/tari_indexer/src/substate_manager.rs (5)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (1)
list_utxos(116-132)clients/tari_indexer_client/src/rest_api_client.rs (1)
list_utxos(174-176)bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)bindings/src/types/Utxo.ts (1)
Utxo(4-4)
crates/wallet/sdk_services/src/indexer_rest_api.rs (1)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
GetUtxosRequest(6-9)
crates/wallet/crypto/src/stealth.rs (2)
crates/engine_types/src/crypto/messages.rs (1)
stealth_statement_metadata64(74-79)crates/wallet/crypto/src/balance_proof.rs (1)
generate_stealth_balance_proof_signature(38-55)
applications/tari_wallet_cli/src/command/transaction.rs (5)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)crates/wallet/sdk/src/models/account.rs (2)
owner_key_id(33-35)owner_key_id(95-97)crates/wallet/sdk/src/models/key.rs (1)
for_account(298-303)bindings/src/types/wallet-daemon-client/TransactionSubmitRequest.ts (1)
TransactionSubmitRequest(5-21)
applications/tari_walletd/src/handlers/transaction.rs (5)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)crates/wallet/sdk/src/models/account.rs (2)
owner_key_id(33-35)owner_key_id(95-97)applications/tari_walletd/src/handlers/helpers.rs (1)
invalid_params(162-173)crates/wallet/sdk/src/models/key.rs (1)
for_account(298-303)
applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts (2)
bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)bindings/src/helpers/consts.ts (1)
XTR(10-10)
applications/tari_indexer/src/rest_api/handlers/utxos.rs (6)
bindings/src/types/tari-indexer-client/GetUtxosRequest.ts (1)
GetUtxosRequest(6-9)bindings/src/types/tari-indexer-client/GetUtxosResponse.ts (1)
GetUtxosResponse(5-5)bindings/src/types/tari-indexer-client/ListUtxosRequest.ts (1)
ListUtxosRequest(5-5)bindings/src/types/tari-indexer-client/ListUtxosResponse.ts (1)
ListUtxosResponse(5-5)applications/tari_indexer/src/substate_manager.rs (1)
list_utxos(143-153)clients/tari_indexer_client/src/rest_api_client.rs (1)
list_utxos(174-176)
crates/wallet/crypto/tests/stealth_transfer_statement.rs (3)
crates/template_test_tooling/src/support/stealth.rs (1)
inputs(204-215)crates/wallet/crypto/src/stealth.rs (2)
output_statements(123-153)create_outputs_statement(119-162)crates/wallet/crypto/src/balance_proof.rs (1)
generate_stealth_balance_proof_signature(38-55)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
applications/tari_indexer/src/store.rs (1)
utxos_list(153-158)
bindings/src/types/wallet-daemon-client/ConfidentialTransferRequest.ts (3)
bindings/src/types/wallet-daemon-client/ComponentAddressOrName.ts (1)
ComponentAddressOrName(4-4)bindings/src/types/Amount.ts (1)
Amount(12-12)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (2)
bindings/src/types/OotleAddress.ts (1)
OotleAddress(3-3)bindings/src/types/Amount.ts (1)
Amount(12-12)
crates/wallet/sdk/src/apis/confidential_transfer.rs (3)
crates/wallet/sdk/src/sdk.rs (2)
network(189-191)transaction_api(220-222)crates/wallet/sdk/src/apis/transaction.rs (1)
new(40-45)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
crates/p2p/src/conversions/transaction.rs (2)
crates/template_lib_types/src/crypto/scalar.rs (1)
from_bytes(32-43)crates/engine_types/src/substate.rs (3)
from_bytes(98-100)from_bytes(197-199)from_bytes(787-789)
utilities/traffic-sim/src/main.rs (5)
bindings/src/types/ComponentAddress.ts (1)
ComponentAddress(6-6)bindings/src/types/ResourceAddress.ts (1)
ResourceAddress(6-6)bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)utilities/traffic-sim/src/sim.rs (1)
wallets(113-115)clients/wallet_daemon_client/src/lib.rs (1)
endpoint(166-168)
integration_tests/src/wallet_daemon_client.rs (6)
bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)bindings/src/types/Account.ts (1)
Account(6-14)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)crates/wallet/sdk/src/models/account.rs (3)
owner_key_id(33-35)owner_key_id(95-97)account(75-77)crates/wallet/sdk/src/models/key.rs (1)
for_account(298-303)
crates/wallet/sdk/src/apis/stealth_transfer/api.rs (2)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)
applications/tari_walletd/src/handlers/accounts.rs (10)
bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
TransferOutput(6-24)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)bindings/src/types/wallet-daemon-client/KeyId.ts (1)
KeyId(3-3)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)crates/wallet/sdk/src/models/account.rs (2)
account(75-77)new(71-73)applications/tari_walletd/src/handlers/helpers.rs (3)
get_account(113-124)not_found(183-190)invalid_params(162-173)crates/wallet/sdk/src/models/key.rs (2)
new(294-296)derived(322-324)crates/wallet/sdk/src/models/lock_guard.rs (1)
lock_id(26-28)
crates/template_lib/src/models/stealth.rs (6)
bindings/src/types/StealthOutputsStatement.ts (1)
StealthOutputsStatement(9-24)bindings/src/types/Amount.ts (1)
Amount(12-12)bindings/src/types/RangeProofBytes.ts (1)
RangeProofBytes(9-9)bindings/src/types/StealthTransferStatement.ts (1)
StealthTransferStatement(5-13)bindings/src/types/RistrettoPublicKeyBytes.ts (1)
RistrettoPublicKeyBytes(6-6)bindings/src/types/StealthInputsStatement.ts (1)
StealthInputsStatement(9-22)
utilities/traffic-sim/src/sim.rs (6)
clients/tari_indexer_client/src/rest_api_client.rs (1)
connect(53-66)clients/wallet_daemon_client/src/lib.rs (2)
connect(149-164)endpoint(166-168)crates/wallet/sdk/src/models/account.rs (5)
address(83-85)new(71-73)account(75-77)component_address(25-27)component_address(79-81)crates/transaction/src/v1/unsigned.rs (2)
new(41-60)builder(37-39)crates/engine_types/src/resource.rs (2)
divisibility(211-213)token_symbol(207-209)crates/template_lib_types/src/amount/amount.rs (1)
to_decimal_string(322-327)
crates/engine_types/src/stealth/transfer.rs (1)
crates/engine_types/src/crypto/helpers.rs (1)
try_decode_to_signature(91-93)
crates/template_test_tooling/src/support/stealth.rs (6)
crates/transaction/src/v1/unsigned.rs (1)
inputs(80-82)crates/transaction/src/v1/transaction.rs (1)
inputs(85-87)crates/transaction/src/unsigned_transaction.rs (1)
inputs(78-82)crates/transaction/src/transaction.rs (1)
inputs(123-127)crates/template_test_tooling/src/support/confidential.rs (1)
inputs(170-176)crates/wallet/sdk/src/apis/stealth_outputs.rs (1)
outputs(692-692)
applications/tari_walletd/web_ui/src/routes/StealthUtxoList/StealthUtxoList.tsx (2)
crates/engine_types/src/resource.rs (1)
divisibility(211-213)applications/tari_walletd/web_ui/src/utils/helpers.tsx (1)
bigintToDecimalString(233-253)
applications/tari_walletd/web_ui/src/routes/FlowEditor/FlowEditor.tsx (1)
bindings/src/types/wallet-daemon-client/KeyBranch.ts (1)
KeyBranch(3-10)
applications/tari_walletd/src/handlers/stealth_utxos.rs (5)
applications/tari_walletd/src/handlers/helpers.rs (1)
invalid_params(162-173)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
StealthUtxosDecryptValueRequest(5-11)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
StealthUtxosDecryptValueResponse(4-4)crates/wallet/crypto/src/value_lookup/io_reader_value_lookup.rs (3)
lookup(90-101)load(26-35)range(82-84)crates/wallet/crypto/src/value_lookup/mod.rs (1)
lookup(19-21)
clients/wallet_daemon_client/src/types.rs (14)
integration_tests/src/wallet_daemon_client.rs (1)
confidential_transfer(877-920)bindings/src/types/UtxoInputSelection.ts (1)
UtxoInputSelection(3-3)crates/engine/src/runtime/impl.rs (1)
stealth_transfer(2760-2776)crates/template_lib/src/models/bucket.rs (1)
stealth_transfer(118-133)bindings/src/types/wallet-daemon-client/TransferOutput.ts (1)
TransferOutput(6-24)bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/StealthTransferStatement.ts (1)
StealthTransferStatement(5-13)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
TransferStatementRequest(7-12)bindings/src/types/wallet-daemon-client/InputSelection.ts (1)
InputSelection(5-5)crates/wallet/sdk/src/apis/stealth_transfer/params.rs (2)
total_output_amount(100-102)total_output_amount(124-126)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1)
StealthTransferRequest(8-17)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
StealthUtxosDecryptValueResponse(4-4)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: test
- GitHub Check: check stable
- GitHub Check: check nightly
- GitHub Check: clippy
- GitHub Check: machete
- GitHub Check: file licenses
| seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id.expect("no owner_key_id")), | ||
| other_signers: vec![], | ||
| detect_inputs: true, | ||
| detect_inputs_use_unversioned: use_unversioned_inputs, | ||
| proof_ids: vec![], | ||
| lock_ids: vec![], | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
Use BranchAndKeyId::for_account(...) instead of new(...)
Replace the remaining BranchAndKeyId::new(...) with for_account(...) for consistency and to avoid API drift/compile errors.
- seal_signer: BranchAndKeyId::new(KeyBranch::Account, account.owner_key_id.expect("no owner_key_id")),
+ seal_signer: BranchAndKeyId::for_account(account.owner_key_id.expect("no owner_key_id")),🏁 Script executed:
#!/bin/bash
# Ensure no other uses of BranchAndKeyId::new remain
rg -nP 'BranchAndKeyId::new\s*\(' -C2Length of output: 1939
Replace all remaining BranchAndKeyId::new(KeyBranch::Account, ...) with for_account(...) for consistency
Verification found three instances requiring the same refactor pattern:
utilities/traffic-sim/src/sim.rs:377integration_tests/tests/steps/wallet_daemon.rs:130integration_tests/src/wallet_daemon_client.rs:952
Update all three to use BranchAndKeyId::for_account(...) instead of the explicit constructor.
🤖 Prompt for AI Agents
In integration_tests/src/wallet_daemon_client.rs around lines 952–957 (and also
update utilities/traffic-sim/src/sim.rs:377 and
integration_tests/tests/steps/wallet_daemon.rs:130), replace the explicit
constructor call BranchAndKeyId::new(KeyBranch::Account,
account.owner_key_id.expect("no owner_key_id")) with the canonical helper
BranchAndKeyId::for_account(account.owner_key_id.expect("no owner_key_id"));
apply the same replacement at the other two locations so all uses are consistent
and retain the existing expect message.
| let file_size = (cli.max - cli.min + 1) * 32 + 20; | ||
| // Rough estimate: 200ms per 10,000 values on a "typical" cpu | ||
| let est_time = Duration::from_millis((cli.max - cli.min + 1) / 10000 * 200); | ||
| println!( | ||
| "Generating Ristretto value lookup table from {} to {} and writing to {} ({}). This will take roughly {} to \ | ||
| complete.", | ||
| "Generating Ristretto value lookup table from {} to {} and writing to {} ({}).", | ||
| cli.min, | ||
| cli.max, | ||
| dest_file.display(), | ||
| human_bytes(file_size as f64), | ||
| humantime::format_duration(est_time) | ||
| ); |
There was a problem hiding this comment.
Guard against invalid range (min > max) to avoid u64 underflow.
Without a check, (cli.max - cli.min + 1) can underflow and produce a huge file_size.
Apply:
let dest_file = cli.output_file;
+ if cli.min > cli.max {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ format!("min ({}) must be <= max ({})", cli.min, cli.max),
+ ));
+ }
+
if cli.validate {Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In utilities/generate_ristretto_value_lookup/src/main.rs around lines 60 to 67,
the computation of file_size uses (cli.max - cli.min + 1) which will underflow
if cli.min > cli.max; add an explicit guard that checks if cli.min > cli.max and
handle it by returning an error (or printing a clear message and exiting with
non-zero status) before computing file_size, or alternatively normalize the
range (swap or use checked subtraction) so the size calculation cannot
underflow; ensure the guard triggers prior to any arithmetic and prevents
continuing with an invalid range.
| async fn write_output_async<W: io::Write>(mut writer: W, min: u64, max: u64, num_threads: usize) -> io::Result<()> { | ||
| // Write header VLKP || min_value (8 bytes) || max_value (8 bytes) | ||
| writer.write_all(b"VLKP")?; | ||
| writer.write_all(&min.to_be_bytes())?; | ||
| writer.write_all(&max.to_be_bytes())?; | ||
|
|
||
| println!( | ||
| "Using {} worker threads to generate Ristretto public keys.", | ||
| num_threads | ||
| ); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Ensure num_threads >= 1 inside the generator.
Defensive clamp prevents a misconfigured CLI (e.g., 0 jobs) from producing an empty body.
Apply:
-async fn write_output_async<W: io::Write>(mut writer: W, min: u64, max: u64, num_threads: usize) -> io::Result<()> {
+async fn write_output_async<W: io::Write>(mut writer: W, min: u64, max: u64, mut num_threads: usize) -> io::Result<()> {
+ if num_threads == 0 {
+ num_threads = 1;
+ }🤖 Prompt for AI Agents
In utilities/generate_ristretto_value_lookup/src/main.rs around lines 92 to 102,
the generator assumes num_threads > 0 which allows a misconfigured CLI (e.g., 0
jobs) to produce an empty body; clamp num_threads to at least 1 before using it
in the generator (e.g., replace usage with a local let num_threads = if
num_threads == 0 { 1 } else { num_threads } or use num_threads =
num_threads.max(1)) so the code always spawns at least one worker thread and the
output body is never empty.
| let (i, mut results) = handles.next().await.expect("handles stream end")?; | ||
| for pk_bytes in &results { | ||
| count += 1; | ||
| writer.write_all(pk_bytes)?; | ||
| } | ||
| results.clear(); | ||
| scratch_pad[i].replace(results); | ||
|
|
There was a problem hiding this comment.
Fix JoinError propagation; ? doesn’t convert JoinError to io::Error.
Map JoinError to io::Error to compile cleanly.
Apply:
- let (i, mut results) = handles.next().await.expect("handles stream end")?;
+ let (i, mut results) = handles
+ .next()
+ .await
+ .expect("handles stream end")
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let (i, mut results) = handles.next().await.expect("handles stream end")?; | |
| for pk_bytes in &results { | |
| count += 1; | |
| writer.write_all(pk_bytes)?; | |
| } | |
| results.clear(); | |
| scratch_pad[i].replace(results); | |
| let (i, mut results) = handles | |
| .next() | |
| .await | |
| .expect("handles stream end") | |
| .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; | |
| for pk_bytes in &results { | |
| count += 1; | |
| writer.write_all(pk_bytes)?; | |
| } | |
| results.clear(); | |
| scratch_pad[i].replace(results); |
🤖 Prompt for AI Agents
utilities/generate_ristretto_value_lookup/src/main.rs around lines 148 to 155:
the code uses `?` on the result of the spawned-task join which yields a
JoinError, but `?` cannot convert JoinError into io::Error; change the join
error handling to map the JoinError into an io::Error before using `?` (e.g.,
call `.map_err(|je| std::io::Error::new(std::io::ErrorKind::Other,
je.to_string()))?` on the join result), leaving the rest of the loop (count
increment, writer.write_all, clearing and replacing scratch_pad) unchanged.
| pub async fn send_random_transaction( | ||
| &mut self, | ||
| id: usize, | ||
| resource_address: ResourceAddress, | ||
| min_value: u64, | ||
| max_value: u64, | ||
| ) -> anyhow::Result<()> { | ||
| if self.wallets.len() < 2 { | ||
| return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions")); | ||
| } | ||
|
|
||
| let mut rng = rand::thread_rng(); | ||
| let sender_idx = rng.gen_range(0..self.accounts.len()); | ||
| let mut receiver_idx = rng.gen_range(0..self.accounts.len()); | ||
|
|
||
| while receiver_idx == sender_idx { | ||
| receiver_idx = rng.gen_range(0..self.accounts.len()); | ||
| } | ||
|
|
||
| let sender_account = &self.accounts[sender_idx]; | ||
| let sender_wallet = &self.wallets[sender_idx]; | ||
| let receiver_address = &self.accounts[receiver_idx]; | ||
| let receiver_wallet = &self.wallets[receiver_idx]; | ||
|
|
||
| let amount_to_send = rng.gen_range(min_value..=max_value); | ||
|
|
||
| log::info!( | ||
| "Sending {} ootle from {} to {}", | ||
| amount_to_send, | ||
| sender_wallet.name, | ||
| receiver_wallet.name | ||
| ); | ||
|
|
||
| let sender = &self.wallets[sender_idx]; | ||
| let mut sender_client = sender.client.clone(); | ||
|
|
||
| let resp = sender_client | ||
| .accounts_stealth_transfer(StealthTransferRequest { | ||
| owner_account: (*sender_account.component_address()).into(), | ||
| fee_input_selection: UtxoInputSelection::PreferConfidential, | ||
| input_selection: UtxoInputSelection::ConfidentialOnly, | ||
| resource_address, | ||
| badge_usage: Default::default(), | ||
| transfers: vec![StealthTransfer { | ||
| destination_address: receiver_address.address().clone(), | ||
| blinded_output_amount: amount_to_send.into(), | ||
| revealed_output_amount: Default::default(), | ||
| output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()), | ||
| }], | ||
| max_fee: 1000, | ||
| dry_run: false, | ||
| }) | ||
| .await?; | ||
|
|
||
| log::info!( | ||
| "Tx {} --> {}: {}", | ||
| sender_wallet.name, | ||
| receiver_wallet.name, | ||
| // resp.status, | ||
| // resp.result.as_ref().and_then(|r| r.result.any_reject()).display(), | ||
| resp.transaction_id, | ||
| ); | ||
|
|
||
| // Placeholder implementation - this will need to be updated based on actual API | ||
| log::info!( | ||
| "send transaction of {} from {} to {}", | ||
| amount_to_send, | ||
| sender_account, | ||
| receiver_address | ||
| ); | ||
|
|
||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
Verify index bounds match.
Lines 206-207 select random indices from self.accounts.len(), but Line 214 and 216 access self.wallets[sender_idx] and self.wallets[receiver_idx]. This assumes wallets.len() == accounts.len(). While setup_accounts() maintains this invariant, add a runtime check at the beginning of this method to prevent potential index out-of-bounds panics.
Apply this diff to add a defensive check:
pub async fn send_random_transaction(
&mut self,
id: usize,
resource_address: ResourceAddress,
min_value: u64,
max_value: u64,
) -> anyhow::Result<()> {
if self.wallets.len() < 2 {
return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions"));
}
+
+ if self.wallets.len() != self.accounts.len() {
+ return Err(anyhow::anyhow!(
+ "Wallets and accounts vectors are misaligned ({} wallets vs {} accounts)",
+ self.wallets.len(),
+ self.accounts.len()
+ ));
+ }
let mut rng = rand::thread_rng();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pub async fn send_random_transaction( | |
| &mut self, | |
| id: usize, | |
| resource_address: ResourceAddress, | |
| min_value: u64, | |
| max_value: u64, | |
| ) -> anyhow::Result<()> { | |
| if self.wallets.len() < 2 { | |
| return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions")); | |
| } | |
| let mut rng = rand::thread_rng(); | |
| let sender_idx = rng.gen_range(0..self.accounts.len()); | |
| let mut receiver_idx = rng.gen_range(0..self.accounts.len()); | |
| while receiver_idx == sender_idx { | |
| receiver_idx = rng.gen_range(0..self.accounts.len()); | |
| } | |
| let sender_account = &self.accounts[sender_idx]; | |
| let sender_wallet = &self.wallets[sender_idx]; | |
| let receiver_address = &self.accounts[receiver_idx]; | |
| let receiver_wallet = &self.wallets[receiver_idx]; | |
| let amount_to_send = rng.gen_range(min_value..=max_value); | |
| log::info!( | |
| "Sending {} ootle from {} to {}", | |
| amount_to_send, | |
| sender_wallet.name, | |
| receiver_wallet.name | |
| ); | |
| let sender = &self.wallets[sender_idx]; | |
| let mut sender_client = sender.client.clone(); | |
| let resp = sender_client | |
| .accounts_stealth_transfer(StealthTransferRequest { | |
| owner_account: (*sender_account.component_address()).into(), | |
| fee_input_selection: UtxoInputSelection::PreferConfidential, | |
| input_selection: UtxoInputSelection::ConfidentialOnly, | |
| resource_address, | |
| badge_usage: Default::default(), | |
| transfers: vec![StealthTransfer { | |
| destination_address: receiver_address.address().clone(), | |
| blinded_output_amount: amount_to_send.into(), | |
| revealed_output_amount: Default::default(), | |
| output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()), | |
| }], | |
| max_fee: 1000, | |
| dry_run: false, | |
| }) | |
| .await?; | |
| log::info!( | |
| "Tx {} --> {}: {}", | |
| sender_wallet.name, | |
| receiver_wallet.name, | |
| // resp.status, | |
| // resp.result.as_ref().and_then(|r| r.result.any_reject()).display(), | |
| resp.transaction_id, | |
| ); | |
| // Placeholder implementation - this will need to be updated based on actual API | |
| log::info!( | |
| "send transaction of {} from {} to {}", | |
| amount_to_send, | |
| sender_account, | |
| receiver_address | |
| ); | |
| Ok(()) | |
| } | |
| pub async fn send_random_transaction( | |
| &mut self, | |
| id: usize, | |
| resource_address: ResourceAddress, | |
| min_value: u64, | |
| max_value: u64, | |
| ) -> anyhow::Result<()> { | |
| if self.wallets.len() < 2 { | |
| return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions")); | |
| } | |
| if self.wallets.len() != self.accounts.len() { | |
| return Err(anyhow::anyhow!( | |
| "Wallets and accounts vectors are misaligned ({} wallets vs {} accounts)", | |
| self.wallets.len(), | |
| self.accounts.len() | |
| )); | |
| } | |
| let mut rng = rand::thread_rng(); | |
| let sender_idx = rng.gen_range(0..self.accounts.len()); | |
| let mut receiver_idx = rng.gen_range(0..self.accounts.len()); | |
| while receiver_idx == sender_idx { | |
| receiver_idx = rng.gen_range(0..self.accounts.len()); | |
| } | |
| let sender_account = &self.accounts[sender_idx]; | |
| let sender_wallet = &self.wallets[sender_idx]; | |
| let receiver_address = &self.accounts[receiver_idx]; | |
| let receiver_wallet = &self.wallets[receiver_idx]; | |
| let amount_to_send = rng.gen_range(min_value..=max_value); | |
| log::info!( | |
| "Sending {} ootle from {} to {}", | |
| amount_to_send, | |
| sender_wallet.name, | |
| receiver_wallet.name | |
| ); | |
| let sender = &self.wallets[sender_idx]; | |
| let mut sender_client = sender.client.clone(); | |
| let resp = sender_client | |
| .accounts_stealth_transfer(StealthTransferRequest { | |
| owner_account: (*sender_account.component_address()).into(), | |
| fee_input_selection: UtxoInputSelection::PreferConfidential, | |
| input_selection: UtxoInputSelection::ConfidentialOnly, | |
| resource_address, | |
| badge_usage: Default::default(), | |
| transfers: vec![StealthTransfer { | |
| destination_address: receiver_address.address().clone(), | |
| blinded_output_amount: amount_to_send.into(), | |
| revealed_output_amount: Default::default(), | |
| output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()), | |
| }], | |
| max_fee: 1000, | |
| dry_run: false, | |
| }) | |
| .await?; | |
| log::info!( | |
| "Tx {} --> {}: {}", | |
| sender_wallet.name, | |
| receiver_wallet.name, | |
| // resp.status, | |
| // resp.result.as_ref().and_then(|r| r.result.any_reject()).display(), | |
| resp.transaction_id, | |
| ); | |
| // Placeholder implementation - this will need to be updated based on actual API | |
| log::info!( | |
| "send transaction of {} from {} to {}", | |
| amount_to_send, | |
| sender_account, | |
| receiver_address | |
| ); | |
| Ok(()) | |
| } |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (1)
57-65: Iterate with Object.entries and fix message text.Cleaner iteration with better type inference; also fix the copy.
Apply this diff:
- Object.keys(balance?.values).map((key) => { - return ( - <Box key={key}> - <Typography> - {key}: {balance.values[key]?.toString() || "Failed not decrypt value"} - </Typography> - </Box> - ); - }); + Object.entries(balance.values).map(([key, value]) => ( + <Box key={key}> + <Typography> + {key}: {value != null ? value.toString() : "Failed to decrypt value"} + </Typography> + </Box> + ));
♻️ Duplicate comments (5)
applications/tari_indexer/src/storage_sqlite/reader.rs (1)
578-587: Unaddressed past review: NULL subquery returns empty results for invalid from_id.The past review comment on lines 563-607 correctly identified that if
from_idreferences a non-existent commitment, the subquery yields NULL andid.gt(NULL)returns no rows. This issue remains unaddressed.As suggested in the previous review, resolve the
start_idfirst:if let Some(from_id) = from_id { - let uxo = alias!(utxos as uxo); - let subquery = uxo - .select(uxo.field(utxos::id)) + let start_id: Option<i32> = utxos::table + .select(utxos::id) .filter(uxo.field(utxos::commitment).eq(from_id.to_commitment_hex_string())) - .limit(1) - .single_value() - .assume_not_null(); - query = query.filter(utxos::id.gt(subquery)); + .first::<i32>(self.connection()) + .optional() + .map_err(|e| StorageError::QueryError { + reason: format!("{OPERATION}: failed to resolve from_id: {}", e), + })?; + + if let Some(id) = start_id { + query = query.filter(utxos::id.gt(id)); + } + // If start_id is None, pagination starts from the beginning }applications/tari_walletd/src/handlers/accounts.rs (2)
1132-1138: Must sign with account key when revealed funds come FromBucket.Line 1132 only checks if locked inputs include revealed funds. If revealed funds are provided via
FromBucket, the account signer is also required. This is the same issue identified in the previous review.Apply:
- let must_sign_with_account_key = inputs.as_ref().is_some_and(|i| i.revealed.is_positive()); + let must_sign_with_account_key = + inputs.as_ref().is_some_and(|i| i.revealed.is_positive()) || + req.input_selection.as_from_bucket().is_some_and(|a| a.is_positive());Based on learnings
1163-1173: checked_add_positive may reject zero; compute conditionally.Using
checked_add_positivewith a zero addend can error. This is the same issue identified in the previous review. Only add when positive, otherwise pass the base amount unchanged.Apply:
- input_revealed_amount: req - .input_selection - .as_from_bucket() - .unwrap_or(Amount::zero()) - .checked_add_positive(inputs.as_ref().map(|i| i.revealed).unwrap_or(Amount::zero())) - .ok_or_else(|| { - invalid_params( - "input_revealed_amount", - Some("input revealed amount overflowed or was negative"), - ) - })?, + input_revealed_amount: { + let mut total = req.input_selection.as_from_bucket().unwrap_or(Amount::zero()); + if let Some(i) = inputs.as_ref() { + if i.revealed.is_positive() { + total = total.checked_add_positive(i.revealed).ok_or_else(|| { + invalid_params( + "input_revealed_amount", + Some("input revealed amount overflowed"), + ) + })?; + } + } + total + },Based on learnings
utilities/traffic-sim/src/sim.rs (2)
233-238: Remove duplicate placeholder log.This duplicates earlier logging and adds little value.
- log::info!( - "send transaction of {} from {} to {}", - amount_to_send, - sender_account, - receiver_address - );
179-189: Defend against index misalignment and invalid ranges.Potential panic if accounts < 2, wallets != accounts, or min_value > max_value. Add guards.
) -> anyhow::Result<()> { - if self.wallets.len() < 2 { + if self.wallets.len() < 2 { return Err(anyhow::anyhow!("Need at least 2 wallets to send transactions")); } + if self.accounts.len() < 2 { + return Err(anyhow::anyhow!("Need at least 2 accounts to send transactions")); + } + if self.wallets.len() != self.accounts.len() { + return Err(anyhow::anyhow!( + "Wallets and accounts vectors are misaligned ({} wallets vs {} accounts)", + self.wallets.len(), + self.accounts.len() + )); + } + if min_value > max_value { + return Err(anyhow::anyhow!( + "min_value ({}) must be <= max_value ({})", + min_value, + max_value + )); + } let mut rng = rand::thread_rng(); let sender_idx = rng.gen_range(0..self.accounts.len()); let mut receiver_idx = rng.gen_range(0..self.accounts.len());
🧹 Nitpick comments (5)
utilities/traffic-sim/src/sim.rs (5)
113-116: Return slice instead of &Vec in accessor.Prefer &[T] to avoid leaking the concrete container type.
- pub fn wallets(&self) -> &Vec<Wallet> { - &self.wallets - } + pub fn wallets(&self) -> &[Wallet] { + &self.wallets + }
329-347: Build funding transaction for the exchange wallet’s network.You’re constructing and submitting the tx with the exchange wallet; use its network to avoid subtle mismatches if wallets differ.
- let transaction = Transaction::builder() - .for_network(wallet.network.as_byte()) + let transaction = Transaction::builder() + .for_network(exchange_wallet.network.as_byte()) .fee_transaction_pay_from_component(*exchange_account.component_address(), 500)Please confirm that all swarm wallets always share the same network; if not, this change is required. Based on context.
423-424: Use warn! for failed transactions.Failures are noteworthy; prefer warn! over info!.
- log::info!("Transaction failed: {:?}", e); + log::warn!("Transaction failed: {:?}", e);
107-111: Drop unnecessary mut binding.
exchange_walletis not mutated in this scope.- let mut exchange_wallet = self.connect_exchange_wallet().await?; + let exchange_wallet = self.connect_exchange_wallet().await?;
566-573: Flush CSV writer before returning.Ensure records are persisted.
- Ok(()) + if let Some(writer) = csv.as_mut() { + writer.flush()?; + } + Ok(())
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
applications/tari_indexer/src/storage_sqlite/reader.rs(2 hunks)applications/tari_walletd/src/handlers/accounts.rs(7 hunks)applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx(2 hunks)applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts(3 hunks)utilities/traffic-sim/src/sim.rs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- applications/tari_walletd/web_ui/src/services/api/hooks/useAccounts.ts
🧰 Additional context used
🧬 Code graph analysis (4)
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (2)
bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueResponse.ts (1)
StealthUtxosDecryptValueResponse(4-4)applications/tari_walletd/web_ui/src/utils/json_rpc.ts (1)
stealthDecryptUtxoBalance(314-316)
applications/tari_indexer/src/storage_sqlite/reader.rs (4)
applications/tari_indexer/src/store.rs (1)
utxos_list(153-158)crates/template_lib/src/models/utxo.rs (2)
resource_address(31-33)id(35-37)bindings/src/types/UtxoId.ts (1)
UtxoId(3-3)bindings/src/types/Utxo.ts (1)
Utxo(4-4)
applications/tari_walletd/src/handlers/accounts.rs (7)
bindings/src/types/wallet-daemon-client/BranchAndKeyId.ts (1)
BranchAndKeyId(5-5)bindings/src/types/wallet-daemon-client/KeyId.ts (1)
KeyId(3-3)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementRequest.ts (1)
AccountsCreateStealthTransferStatementRequest(4-4)bindings/src/types/wallet-daemon-client/AccountsCreateStealthTransferStatementResponse.ts (1)
AccountsCreateStealthTransferStatementResponse(5-9)applications/tari_walletd/src/handlers/helpers.rs (3)
get_account(113-124)not_found(183-190)invalid_params(162-173)crates/wallet/sdk/src/models/key.rs (2)
new(294-296)derived(322-324)crates/wallet/sdk/src/models/lock_guard.rs (1)
lock_id(26-28)
utilities/traffic-sim/src/sim.rs (9)
bindings/src/types/wallet-daemon-client/StealthTransferRequest.ts (1)
StealthTransferRequest(8-17)bindings/src/types/wallet-daemon-client/StealthUtxosDecryptValueRequest.ts (1)
StealthUtxosDecryptValueRequest(5-11)bindings/src/types/wallet-daemon-client/TransferStatementRequest.ts (1)
TransferStatementRequest(7-12)clients/tari_indexer_client/src/rest_api_client.rs (1)
connect(53-66)clients/wallet_daemon_client/src/lib.rs (2)
connect(149-164)endpoint(166-168)crates/wallet/sdk/src/models/account.rs (5)
address(83-85)new(71-73)account(75-77)component_address(25-27)component_address(79-81)crates/transaction/src/v1/unsigned.rs (2)
new(41-60)builder(37-39)crates/wallet/crypto/src/memo.rs (1)
new_message(42-46)crates/template_lib_types/src/amount/amount.rs (1)
to_decimal_string(322-327)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: clippy
- GitHub Check: test
- GitHub Check: check nightly
🔇 Additional comments (12)
applications/tari_indexer/src/storage_sqlite/reader.rs (2)
417-417: LGTM! Correct use of aliased table reference.The change to use
tr.field(transaction_receipts::address)is the proper Diesel pattern for referencing columns in aliased subqueries.
572-576: Good fix: is_burnt filter now included.The addition of
.filter(utxos::is_burnt.eq(false))on line 575 correctly addresses the first concern from the past review, ensuring burnt UTXOs are excluded from the listing.applications/tari_walletd/src/handlers/accounts.rs (8)
4-4: LGTM: Import additions support new functionality.The new imports are all utilized in the new
handle_create_stealth_transfer_statementfunction and related changes.Also applies to: 6-6, 29-29, 33-33, 60-61
367-374: LGTM: Improved error handling with explicit not_found.The change provides a clearer error message when an account is not found, consistent with similar patterns in
handle_get_by_key_index(lines 388-390) andhandle_create_or_get(lines 160-162).
551-551: LGTM: More idiomatic single-element iterator construction.Using
iter::onceis cleaner thanarray::from_reffor creating single-element iterators.Also applies to: 553-553
982-982: LGTM: New field wired through correctly.The
fee_input_selectionfield is properly threaded from the request toStealthTransferParams.
1077-1089: LGTM: Proper batch size validation.The validation ensures at least one request and enforces a maximum of 16 requests, which is reasonable for batch processing.
1091-1094: LGTM: Lock guard pattern prevents premature unlock.Using
WalletLockDropGuardensures outputs remain locked if an error occurs beforedisarm()is called at line 1184. This is critical for preventing double-spend attempts.
1106-1114: LGTM: Resource stealth validation addressed.This properly validates that the resource is a stealth resource before proceeding, addressing the concern from the previous review.
Based on learnings
1145-1150: LGTM: Output filtering, collection, and response handling are correct.
- Outputs are properly filtered for positive blinded amounts (line 1148).
- Signers and statements are collected correctly (lines 1179-1180).
- Lock guard is disarmed before returning, leaving outputs locked as intended (line 1184).
- Response structure matches the binding types.
Also applies to: 1179-1180, 1183-1190
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx (1)
31-31: Bindings import update looks correct.Import aligns with the updated wallet-daemon bindings and response shape.
utilities/traffic-sim/src/sim.rs (1)
493-500: Confirm view_key_id = 0 is valid.Hard-coding 0 assumes the default view key; verify against the wallet daemon API and consider making it configurable.
Would you like me to add a CLI/config option for
view_key_id?Also applies to: 546-553
| maximumExpectedValue: 100000000, | ||
| keyId: 0, | ||
| }); |
There was a problem hiding this comment.
Harden BigInt parsing to avoid runtime crashes on blank/invalid input.
BigInt('') and BigInt(non-integer strings) throw; users can clear or type invalid values. Same risk for keyId; minimumExpectedValue also needs validation.
Apply this diff to use a safe parser with sensible fallbacks:
- minimum_expected_value: formState.minimumExpectedValue ? BigInt(formState.minimumExpectedValue) : null,
- maximum_expected_value: BigInt(formState.maximumExpectedValue),
- view_key_id: BigInt(formState.keyId),
+ minimum_expected_value:
+ formState.minimumExpectedValue === null || formState.minimumExpectedValue === ""
+ ? null
+ : safeBigInt(formState.minimumExpectedValue, null),
+ maximum_expected_value: safeBigInt(formState.maximumExpectedValue, 0n),
+ view_key_id: safeBigInt(formState.keyId, 0n),Add this helper outside the component (or top of file):
function safeBigInt<T extends string | number | null | undefined>(
v: T,
fallback: bigint | null,
): bigint | null {
if (v === null || v === undefined) return fallback;
const s = typeof v === "number" ? String(Math.trunc(v)) : v.trim();
if (!/^-?\d+$/.test(s)) return fallback;
try { return BigInt(s); } catch { return fallback; }
}Optional: initialize formState fields as empty strings and set TextField type="number" for numeric inputs to reduce invalid entries.
Also applies to: 47-50
| keyId: 0, | ||
| }); | ||
| const [balance, setBalance] = useState<any>(null); | ||
| const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse>(null); |
There was a problem hiding this comment.
State type must include null to match initialization and guards.
Initial value is null but the state is typed as non-nullable; this will fail type-checking under strict TS.
Apply this diff:
- const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse>(null);
+ const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse | null>(null);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse>(null); | |
| const [balance, setBalance] = useState<StealthUtxosDecryptValueResponse | null>(null); |
🤖 Prompt for AI Agents
In
applications/tari_walletd/web_ui/src/routes/Settings/Components/DecryptUtxoBalance.tsx
around line 41, the useState is initialized with null but typed as
StealthUtxosDecryptValueResponse (non-nullable), causing strict TypeScript
errors; change the state type to allow null (e.g.,
StealthUtxosDecryptValueResponse | null), and update any downstream usage/guards
to handle the null case (keep existing null checks or add conditional
rendering/early returns where state is accessed).
| let response = Client::new() | ||
| .post(&self.swarm_url) | ||
| .json(&json!({ | ||
| "jsonrpc": "2.0", | ||
| "method": "list_instances", | ||
| "params": { "by_type": "TariWalletDaemon" }, | ||
| "id": 1, | ||
| })) | ||
| .send() | ||
| .await?; | ||
|
|
||
| let swarm_response: serde_json::Value = response.json().await?; | ||
| let resp = serde_json::from_value::<SwarmResponse>( | ||
| swarm_response | ||
| .get("result") | ||
| .ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))? | ||
| .clone(), | ||
| )?; | ||
| let addrs = resp.instances.into_iter().filter_map(|instance| { | ||
| if !instance.is_running { | ||
| log::info!("WARN: stopped wallet instance: {}", instance.name); | ||
| } | ||
| let rpc_port = instance.ports.get("jrpc")?; | ||
| Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port))) | ||
| }); | ||
|
|
There was a problem hiding this comment.
Harden swarm discovery: add HTTP timeout, handle JSON-RPC errors, and skip stopped instances.
Without a timeout and JSON-RPC error handling, discovery may hang or misparse failures. Also, you log stopped instances but still try to connect to them.
Apply this diff:
- let response = Client::new()
- .post(&self.swarm_url)
+ let client = reqwest::Client::builder()
+ .timeout(Duration::from_secs(10))
+ .build()?;
+ let response = client
+ .post(&self.swarm_url)
.json(&json!({
"jsonrpc": "2.0",
"method": "list_instances",
"params": { "by_type": "TariWalletDaemon" },
"id": 1,
}))
.send()
.await?;
- let swarm_response: serde_json::Value = response.json().await?;
+ let swarm_response: serde_json::Value = response.json().await?;
+ if let Some(err) = swarm_response.get("error") {
+ return Err(anyhow::anyhow!(format!("Swarm RPC error: {err}")));
+ }
let resp = serde_json::from_value::<SwarmResponse>(
swarm_response
.get("result")
.ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))?
.clone(),
)?;
- let addrs = resp.instances.into_iter().filter_map(|instance| {
- if !instance.is_running {
- log::info!("WARN: stopped wallet instance: {}", instance.name);
- }
- let rpc_port = instance.ports.get("jrpc")?;
- Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
- });
+ let addrs = resp.instances.into_iter().filter_map(|instance| {
+ if !instance.is_running {
+ log::warn!("Stopped wallet instance: {}", instance.name);
+ return None;
+ }
+ let rpc_port = instance.ports.get("jrpc")?;
+ Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port)))
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let response = Client::new() | |
| .post(&self.swarm_url) | |
| .json(&json!({ | |
| "jsonrpc": "2.0", | |
| "method": "list_instances", | |
| "params": { "by_type": "TariWalletDaemon" }, | |
| "id": 1, | |
| })) | |
| .send() | |
| .await?; | |
| let swarm_response: serde_json::Value = response.json().await?; | |
| let resp = serde_json::from_value::<SwarmResponse>( | |
| swarm_response | |
| .get("result") | |
| .ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))? | |
| .clone(), | |
| )?; | |
| let addrs = resp.instances.into_iter().filter_map(|instance| { | |
| if !instance.is_running { | |
| log::info!("WARN: stopped wallet instance: {}", instance.name); | |
| } | |
| let rpc_port = instance.ports.get("jrpc")?; | |
| Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port))) | |
| }); | |
| let client = reqwest::Client::builder() | |
| .timeout(Duration::from_secs(10)) | |
| .build()?; | |
| let response = client | |
| .post(&self.swarm_url) | |
| .json(&json!({ | |
| "jsonrpc": "2.0", | |
| "method": "list_instances", | |
| "params": { "by_type": "TariWalletDaemon" }, | |
| "id": 1, | |
| })) | |
| .send() | |
| .await?; | |
| let swarm_response: serde_json::Value = response.json().await?; | |
| if let Some(err) = swarm_response.get("error") { | |
| return Err(anyhow::anyhow!(format!("Swarm RPC error: {err}"))); | |
| } | |
| let resp = serde_json::from_value::<SwarmResponse>( | |
| swarm_response | |
| .get("result") | |
| .ok_or_else(|| anyhow::anyhow!("No result field in swarm response"))? | |
| .clone(), | |
| )?; | |
| let addrs = resp.instances.into_iter().filter_map(|instance| { | |
| if !instance.is_running { | |
| log::warn!("Stopped wallet instance: {}", instance.name); | |
| return None; | |
| } | |
| let rpc_port = instance.ports.get("jrpc")?; | |
| Some((instance.name, format!("http://localhost:{}/json_rpc", rpc_port))) | |
| }); |
🤖 Prompt for AI Agents
In utilities/traffic-sim/src/sim.rs around lines 138 to 163, the swarm discovery
call lacks an HTTP timeout, doesn't check for JSON-RPC errors in the response,
and still attempts to use stopped instances after only logging them; update the
Client request to set a reasonable timeout (e.g., via
Client::builder().timeout(...)), inspect the parsed JSON for an "error" field
and return a contextual anyhow::Error if present, and filter out instances where
is_running is false (skip them instead of building addresses) while preserving
logging for skipped instances and returning useful errors when parsing or
missing fields occur.
| output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()), | ||
| }], | ||
| max_fee: 1000, |
There was a problem hiding this comment.
Avoid panic: don’t unwrap Memo::new_message.
Memo::new_message returns Option; unwrap() can panic on oversize strings. Pass the Option directly.
- output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()),
+ output_memo: Memo::new_message(format!("Transfer {id}: {amount_to_send}")),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| output_memo: Some(Memo::new_message(format!("Transfer {id}: {amount_to_send}")).unwrap()), | |
| }], | |
| max_fee: 1000, | |
| output_memo: Memo::new_message(format!("Transfer {id}: {amount_to_send}")), | |
| }], | |
| max_fee: 1000, |
🤖 Prompt for AI Agents
In utilities/traffic-sim/src/sim.rs around lines 219–221, the code unwraps
Memo::new_message which returns Option and can panic on oversized strings;
remove the unwrap and pass the Option through directly (e.g., set output_memo to
the result of Memo::new_message(format!(...)) rather than Some(...). This keeps
the field as an Option<Memo> and avoids a potential panic when the message is
too large.
| memo: Some(Memo::new_message(format!("Initial Funding: {fund_amount}")).unwrap()), | ||
| }], |
There was a problem hiding this comment.
Avoid panic: don’t unwrap Memo::new_message in funding statement.
Same unwrap issue as above.
- memo: Some(Memo::new_message(format!("Initial Funding: {fund_amount}")).unwrap()),
+ memo: Memo::new_message(format!("Initial Funding: {fund_amount}")),Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In utilities/traffic-sim/src/sim.rs around lines 323-324, the code calls
Memo::new_message(...).unwrap() which can panic; replace the unwrap with proper
error handling by propagating the Result (use ? if the surrounding function
returns Result) or by handling the Err case explicitly and returning or logging
an error; ensure the created memo field is constructed from the successful
Result (e.g., memo: Some(Memo::new_message(...)?)) or otherwise handle the error
path instead of unwrapping.
Description
feat!: generate stealth statements from wallet api+new sending test
fix: endianness mismatch in value lookup file header
feat: list utxos indexer api
fix: separate input selections strategies for fees and main
fix: multithreaded value ristretto key generator
feat: util that sends funds between wallets in swarm
fix!: set balance proof to None if the transfer statement only involves revealed funds.
Motivation and Context
Allows stealth statements to be generated from API calls, this is used in the new util to send faucet funds as UTXOs.
Also would allow floweditor/manifest to generate stealth statements for built transactions.
Generating a value lookup file for hundreds of millions of values took more than an hour. This PR reduces this to 5-10 minutes.
The new util (traffic sim), funds and transfers funds between all wallets in the swarm. It can also ask the "exchange" wallet to decrypt utxo values.
How Has This Been Tested?
Manually, new unit tests
Breaking Changes
Summary by CodeRabbit
New Features
Improvements
Bug Fixes